ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

轻量 Agent 的第一版:先做少而稳的工具闭环

轻量 Agent 的第一版:先做少而稳的工具闭环 轻量 Agent 的第一版先做少而稳的工具闭环面向 Git 提交处理或代码审查的轻量 Agent首版应先验证工具调用、异常 JSON 处理和循环终止等关键链路。记忆、向量库和多 Agent 协作可按需求后置。MVP 的目标是以较少的组件验证核心任务而不是预先覆盖所有能力。1. 做加法容易做减法难第一版 Agent 到底该砍掉什么搭建 Agent 产品时很多人容易陷入“能力幻觉”。看到 API 接口支持 Tool Calling就想把本地文件的读写、Git 命令行、甚至远程 HTTP 请求一股脑塞给模型。但真实的工程痛点在于模型的注意力窗口随着上下文变长而迅速衰减工具数量越多误触发和参数格式错误的概率就会呈指数级上升。在写第一版时建议做如下减法砍掉长期记忆不要在第一版引入 Vector DB。对话历史直接用内存列表存储设定滑动窗口阈值例如保留最近 6 轮超过即丢弃早期非系统提示词。限制工具数量工具控制在 3 个以内且每个工具入参字段必须标明严格的数据类型和用途描述。放弃多 Agent 协同单 Agent 结合明确的 System Prompt 完全足够应对 90% 的自动化脚本场景不要强行搞“架构师 Agent 程序员 Agent”的复杂戏码。2. 确定性防线用 Python 类型约束与 JSON Schema 拦截模型幻觉大模型最不可靠的就是输出格式。即使在 Prompt 里写了十遍“必须返回纯 JSON 格式”它仍然可能在最前头加上 json 或者在末尾补一句尾巴说明。如果不做确定性拦截后续的代码执行逻辑直接会抛出json.decoder.JSONDecodeError崩溃。针对这种情况第一版必须设置一层轻量的 Python 类型校验器例如基于pydantic或jsonschema。flowchart TD A[用户输入 Prompt] -- B[构建 System Context] B -- C[调用大模型 API] C -- D{响应解析} D -- 格式错误/幻觉 -- E[JSON 自动修补 / 重试拦截器] E -- 超过2次 -- F[触发降级: 返回友好的报错信息] D -- 格式正确 -- G{是否包含 Tool Call?} G -- 是 -- H[检查 Tool 调用计数器] H -- 超过阈值(如5次) -- I[强行截断并提示死循环警告] H -- 未超限 -- J[执行本地工具函数] J -- B G -- 否 -- K[输出最终结果给用户]如上图所示模型响应绝不能直接透传给系统。它必须先通过 JSON 自动修补与格式校验器。如果判定需要执行工具还要经过工具调用计数器的硬性限制防止出现无限循环。3. 工具调用状态机防止 Agent 陷入死循环的硬性上限闸门在使用 Agent 自动执行任务时常常会遇到一种极端情况Agent 调用的工具返回了报错例如文件未找到它接着再次尝试调用同一个工具入参稍微改了一下依然报错于是系统陷入无限重试循环几分钟内消耗掉上百万 Token。为了解决这个问题我们需要在工具调度器中加入硬性防护单次 Request 工具调用上限单个用户请求中Agent 最多只能连续调用 N 次工具例如最多 5 次。重复参数哈希检测如果 Agent 以完全相同的参数连续调用同一个工具 2 次直接拦截并向 Agent 返回“该参数已验证失败请更换策略”。4. 从命令行 CLI 到可运行节点完整生产级 Agent 调度代码下面是一段用 Python 实现的生产级轻量 Agent 调度器代码。它包含了输入校验、超时控制、工具调用计数闸门以及异常捕获机制。import json import time import logging from typing import Dict, Any, List, Callable, Optional from pydantic import BaseModel, Field, ValidationError logging.basicConfig(levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s) # 1. 定义工具入参 Schema class FileReadArgs(BaseModel): file_path: str Field(description需要读取的本地文件相对路径) # 2. 定义系统工具函数 def read_file_tool(file_path: str) - str: 读取指定路径文件内容的真实工具 try: with open(file_path, r, encodingutf-8) as f: content f.read(1000) # 第一版做截断防止大文件爆 Token return f文件内容前1000字符\n{content} except Exception as e: return f读取文件失败: {str(e)} # 注册可调用的工具字典 AVAILABLE_TOOLS: Dict[str, Dict[str, Any]] { read_file: { func: read_file_tool, schema: FileReadArgs, description: 读取本地文件内容 } } class AgentRunner: def __init__(self, max_tool_calls: int 5): self.max_tool_calls max_tool_calls self.history: List[Dict[str, str]] [] def mock_llm_api_call(self, messages: List[Dict[str, str]]) - str: 模拟 LLM 返回。实际生产中替换为 openai / ollama SDK 调用 last_msg messages[-1][content] if 读取 in last_msg and not any(m.get(role) tool for m in messages): # 模拟 LLM 决定调用工具 return json.dumps({ tool: read_file, args: {file_path: README.md} }) return 分析完成项目 README 包含了基本安装说明。 def run(self, user_prompt: str) - str: self.history.append({role: user, content: user_prompt}) tool_call_count 0 while True: # 防线一工具调用上限拦截 if tool_call_count self.max_tool_calls: logging.warning(f工具调用次数已达上限 ({self.max_tool_calls})强行截断循环) return Agent 思考步数过多已自动停止以防止死循环。 # 调用 LLM API try: raw_response self.mock_llm_api_call(self.history) except Exception as exc: logging.error(fLLM API 请求异常: {exc}) return 模型服务响应超时请稍后重试。 # 防线二尝试解析 JSON 工具调用 try: data json.loads(raw_response) if isinstance(data, dict) and tool in data and args in data: tool_name data[tool] tool_args data[args] if tool_name not in AVAILABLE_TOOLS: self.history.append({role: system, content: f未知工具: {tool_name}}) tool_call_count 1 continue # 参数校验 schema_cls AVAILABLE_TOOLS[tool_name][schema] validated_args schema_cls(**tool_args) # 执行真实工具调用 logging.info(f正在执行工具 [{tool_name}] 参数: {validated_args.model_dump()}) tool_func AVAILABLE_TOOLS[tool_name][func] result tool_func(**validated_args.model_dump()) # 将结果喂回历史上下文 self.history.append({role: assistant, content: raw_response}) self.history.append({role: tool, content: f工具 [{tool_name}] 输出: {result}}) tool_call_count 1 continue except (json.JSONDecodeError, ValidationError): # 不是工具调用或者 JSON 格式不合规当做最终文本输出 pass # 正常输出文本 self.history.append({role: assistant, content: raw_response}) return raw_response if __name__ __main__: runner AgentRunner(max_tool_calls3) res runner.run(请帮我读取 README.md 文件的内容) print(f最终输出: {res})5. 灰度验证与效果评估第一版上线后的三个核心收敛指标第一版上线后不需要搭建太复杂的自动化评测集重点观察以下三个工程指标工具调用成功率模型发起的 Tool Call 中参数符合 Schema 校验并成功执行的比例。低于 85% 说明 Prompt 中的工具描述不够明确。平均单请求轮次Turn Count完成一次用户任务所需的 LLM 交互次数。如果平均超过 4 轮说明任务未做合理切分。异常中断率因超时、死循环拦截器或格式解析失败而触发表外降级输出的比例。先保证第一版在小场景下 100% 可可靠运行再渐进式增加更多的工具和复杂的上下文编排才是开源 AI 工具链能稳定迭代下去的务实路径。
返回列表