共计 1949 个字符,预计需要花费 5 分钟才能阅读完成。
背景痛点:新手常遇到的耦合问题
刚开始接触 Agent 开发时,最容易犯的错误就是把模型、工具、指令这三者混在一起写。比如直接把模型调用代码塞进工具类,或者在指令处理中硬编码业务逻辑。这样会导致:

- 改模型要动工具代码
- 加新指令要改模型接口
- 单元测试难以下手
典型的症状是代码里到处能看到 if-else 链条,每个新需求都要在多个文件里打补丁。
架构设计:划清边界是关键
UML 类图示意
@startuml
class Model {+ predict(input: str) -> str
}
class Tool {
- model: Model
+ execute(params: dict) -> dict
}
class Command {- tools: dict[str, Tool]
+ handle(context: dict) -> Response
}
Model <|-- Tool
Tool <-- Command
@enduml
- 模型:纯算法黑盒,只管输入输出
- 工具:组合模型能力,实现具体功能
- 指令:编排工具调用,处理业务流程
架构风格选择
- 单体式(Monolithic)
- 适合:小型固定功能 Agent
-
特点:所有工具编译时绑定
-
微内核(Microkernel)
- 适合:需要动态扩展的场景
- 特点:通过注册表动态加载工具
核心实现:Python 示例
使用 Protocol 定义接口
from typing import Protocol, runtime_checkable
@runtime_checkable
class ToolProtocol(Protocol):
def execute(self, params: dict) -> dict:
...
class TranslatorTool:
def __init__(self, model: Model):
self.model = model
def execute(self, params: dict) -> dict:
try:
text = params['text']
return {'result': self.model.predict(text)}
except KeyError as e:
raise InvalidParamsError(f"Missing param: {e}")
依赖注入实践
from dependency_injector import containers, providers
class ToolsContainer(containers.DeclarativeContainer):
model = providers.Singleton(Model)
translator = providers.Factory(
TranslatorTool,
model=model
)
# 使用时
container = ToolsContainer()
tool = container.translator()
生产环境注意事项
幂等性保障
- 为每个指令生成唯一 trace_id
- 工具层实现操作去重
class CacheTool:
def __init__(self, redis):
self.redis = redis
def execute(self, params):
key = f"op:{params['op_id']}"
if self.redis.get(key):
return {'status': 'already_done'}
# 真实操作...
self.redis.setex(key, 3600, '1')
限流器实现
from ratelimit import limits, sleep_and_retry
class LimitedModel:
@sleep_and_retry
@limits(calls=100, period=60)
def predict(self, text):
return self._real_predict(text)
避坑指南
线程模型选择
- IO 密集型:async/await
- CPU 密集型:线程池 + 任务队列
- 避免在工具间共享可变状态
参数校验技巧
from pydantic import BaseModel
class TranslateParams(BaseModel):
text: str
from_lang: str = 'auto'
to_lang: str
# 在工具中直接校验
def execute(self, params):
validated = TranslateParams(**params)
...
思考题
- 当工具 B 依赖工具 A 的输出时,如何设计超时回滚机制?
- 模型版本切换如何做到不影响正在执行的指令?
- 如何收集工具的执行指标用于容量规划?
写在最后
实际开发中会发现,前期花时间设计清晰的组件边界,后期维护成本能降低 70% 以上。建议先用简单用例验证架构,再逐步添加复杂功能。遇到设计困惑时,可以问自己:这个修改会影响几个组件?如果答案大于 1,可能需要重新审视设计。
正文完
