5.5 外部系统与服务集成


5.5 外部系统与服务集成

Agent 要落地,得接外部世界。纯聊天解决不了"查一下数据库里昨天的销量"。这一节讲 Agent 怎么通过函数安全地接数据库、调 API、消费 Web 服务——核心仍是第三章的函数调用,只是函数体换成真实 IO。

5.5 外部系统与服务集成

接数据库:函数体包一层查询

把数据库查询封装成函数,注册给 Agent。模型生成调用时只传参数,不碰 SQL 拼接细节(降低注入风险)。

import os def query_sales(yesterday: str) -> str: """查询指定日期的销售总额。""" # 真实场景用参数化查询,绝不字符串拼接 sql = "SELECT SUM(amount) FROM orders WHERE day = %s" # cursor.execute(sql, (yesterday,)) -> 返回结果 return "昨日销售额 12800 元" # 示例返回 # 注册后,Agent 可用自然语言触发:查一下昨天的销售额

接内部 API:统一网关

多个函数都调内部服务时,抽一个客户端对象,函数只调它的方法。这样鉴权、重试、超时集中管理,Agent 侧保持干净。

class InternalClient: def __init__(self, token): self.token = token def get_user(self, uid: str): # 带鉴权请求内部用户服务 return {"uid": uid, "name": "示例"} client = InternalClient(os.environ.get("SVC_TOKEN")) def fetch_user(uid: str) -> str: """获取用户信息。""" return str(client.get_user(uid)) # Agent 注册 fetch_user,自然能回答"用户123是谁"

接 Web 服务:超时与重试

外部 Web 服务会抖。函数里必须设超时和有限重试,否则一次慢响应卡住整个对话。我们建议重试不超过 3 次、超时 10 秒。

import requests def call_web_api(endpoint: str) -> str: """调用外部 Web 接口,带超时与重试。""" for i in range(3): try: r = requests.get(endpoint, timeout=10) return r.text[:200] except requests.Timeout: if i == 2: return "调用超时,请稍后" return "调用失败"

集成的安全要点

  • 凭据走环境变量,不进函数体硬编码(见 5.4)。
  • 写操作(增删改)默认需人工确认,只读操作可自动。
  • 所有外部调用加超时,防止卡死对话。

集成的边界:哪些该接、哪些别接

能接不等于该接。我们给一条边界原则:Agent 该接的是"它做不了、外部系统能做"的事——查实时数据、执行写操作、调专有服务;不该接的是"它本就能在对话里解决"的事,比如纯文本润色硬要套个 API。每多一个外部依赖,就多一份版本耦合、超时风险和故障面,所以接之前先问"这部能力离得开框架吗、稳定吗、出错了能隔离吗"。

用生物来类比:共生关系要互利且稳定才该接纳,一个动不动罢工的共生体只会拖垮宿主。判断一个集成值不值得引入,看三点——它解决的是不是编排层解决不了的、它的维护节奏跟不跟得上框架、它的错误能不能被你的兜底捕获而不蔓延。三点有一个不满足,就先别接,用更轻的方式(比如先把结果缓存进来)过渡。

还有个生产必做的设计:失败要"就地转消息"。外部调用超时、返回异常、鉴权失效,都应当在函数内转成一句可读的错误字符串回给对话(前面 call_web_api 的"调用超时,请稍后"就是这个思路),而不是让异常冒泡中断整段对话。这样 Agent 能在下一轮自己决定"重试还是换个说法问用户",系统韧性来自这里。

该接 不该接
查实时数据、执行写操作、调专有服务 对话内就能做的文本处理
稳定、错误可隔离的依赖 动不动罢工、错误会蔓延的依赖
编排层做不了的能力 仅为"显得高级"而加的调用

凭据与依赖的治理

外部集成一多,凭据和版本就成了隐患。凭据上,所有 key、token 必须走环境变量或专用密钥管理,绝不进函数体、不进仓库——前面示例里 client = InternalClient(os.environ.get("SVC_TOKEN")) 就是这个原则。更稳妥的是按服务分桶管理,哪个服务泄露就只换那一个,不牵连全局。多框架(7.2)各自都可能要凭据,集中在一个配置层统一注入,别让各框架散落各处各管各的,否则漏配、错配都难查。

依赖上,AutoGen、LangChain、LlamaIndex 以及你的数据库驱动,都在各自迭代,某个接口三个月一变。集成代码必须锁版本、写清适配区间,升级时单独跑集成回归测试,而不是随手装最新。我们见过团队"pip install --upgrade"后整个检索链路失效,排查半天才发现是某框架改了返回结构。治理的底线:集成相关的依赖,视同生产依赖严管,不随意浮动。

治理项 做法 不做
凭据 环境变量/密钥管理、按服务分桶 硬编码进函数或仓库
版本 锁版本、写适配区间、单独回归 随手 upgrade 全量
配置 统一配置层注入 各框架散落各配

本节要点回顾

  • 数据库/API/Web 都通过函数接入,模型只传参。
  • 客户端对象抽出来统一管理鉴权重试。
  • 外部调用必设超时,写操作需人确认。
  • 接之前判边界,失败就地转消息不中断对话。
  • 凭据走环境变量按服务分桶,依赖锁版本单独回归。
  • 集成治理做到位,外部世界才真正"伸手可得"而不"一碰就崩"。

集成要写专门的测试

接入外部系统后,别只靠手跑验证。给每个外部函数写测试:用mock替代真实数据库/API,验证"参数正确时返回预期、参数异常时转成错误字符串、超时有兜底"。这样框架或依赖升级时,跑一遍集成测试就能知道哪个外部调用被打破。集成测试是外部依赖频繁变动时的安全网,省去每次升级后的手工惊吓。

⚠️ 函数里用字符串拼接 SQL 且参数来自模型,等于敞开 SQL 注入,务必参数化。

💡 外部集成让"对话即编排"从聊天室走进业务系统——手伸出去,才真正干活。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U