news 2026/8/30 5:50:46

JIT-Agent:动态生成智能体框架的设计与实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JIT-Agent:动态生成智能体框架的设计与实现

在搭建智能体(Agent)应用时,最让人头疼的往往不是大模型本身,而是 Agent 的“骨架”怎么搭:工具列表写死、任务流程写死、上下文越堆越长……一旦业务需求变化,静态配置的 Agent 就要改代码、发版本,链路还特别容易断。JIT-Agent 正是为了解决这类问题出现的一种动态生成智能体框架的实现思路。

这里所说的“模型”,并不是指某一个预训练大模型,而是一种框架层面的设计模型:JIT(Just-In-Time,即时生成)。它借鉴了 JIT 编译“按需生成、运行时执行”的思想,把 Agent 中的工具选择、提示词组装、执行计划从启动阶段推迟到每一次任务请求发生时动态完成。本文会从核心概念讲起,再手把手实现一个轻量 JIT-Agent 框架,最后给出常见问题和工程建议。

1. 背景与核心概念

1.1 什么是 JIT-Agent

JIT-Agent 可以理解为一种“动态生成智能体框架”的设计模型。通常一个 Agent 由三部分组成:大模型(LLM)、工具集(Tools)、执行策略(Execution Strategy)。传统做法是在系统启动时把全部工具和固定提示词注册进去,之后所有请求都走同一套逻辑。这种模式实现简单,但灵活性不足。

JIT-Agent 改变了生成时机:当用户请求到达时,框架先分析当前任务,确定“这个任务需要用到哪些工具”,再去注册表中动态加载对应的工具元数据和执行函数,同时生成针对性的系统提示词,最后执行任务并返回结果。整个过程像 JIT 编译一样,不是提前把一切准备好,而是“用到什么才生成什么”。

这样做的好处很明显:

  • 减少上下文中的工具描述,节省 Token;
  • 模型不容易被无关工具干扰;
  • 新增工具时无需修改主流程,只要在注册表中登记即可;
  • 可以根据不同用户、不同场景生成不同形态的 Agent。

1.2 JIT-Agent 解决什么问题

静态 Agent 在实际项目中会遇到几个突出问题。

第一,工具全量注册导致上下文膨胀。假设一个 Agent 注册了 30 个工具,每次调用大模型时都要把 30 个工具的描述传给模型,即使本次任务只需要其中 2 个。随着工具数量增长,Token 开销会越来越大,模型出错的概率也会上升。

第二,任务流程固定,难以应对开放性问题。很多 Agent 是“定义好 Function、定义好 Prompt、执行固定流程”,对简单任务勉强可用,但遇到无法预料的用户输入,就会显得僵化。

第三,扩展成本高。每次新增工具,都要修改 Agent 的初始化代码,甚至要调整提示词模板,维护成本非常高。

JIT-Agent 的核心思路是“以任务为中心”:先把所有工具注册到一个中心注册表,每次请求到来时,由规划器决定加载哪些工具,再动态生成执行计划。这样一来,Agent 的结构与具体业务解耦,新增工具只需要写一个函数并注册,无需改动主框架。

当然,动态生成也不是没有代价。运行时分析任务、动态加载工具都会带来额外延迟,而且规划结果可能不稳定。所以 JIT-Agent 更适合任务类型丰富、工具数量较多、需要快速扩展的场景。

1.3 典型应用场景

JIT-Agent 的适用面很广,常见的有下面几类。

  • 智能客服系统:用户问“我的订单什么时候到”,后台动态加载订单查询工具;用户问“退款流程是什么”,后台加载退款相关文档工具。
  • 数据分析平台:用户输入“帮我画一个 7 月销售额折线图”,Agent 动态加载数据查询工具、图表生成工具,不需要把所有 BI 能力全部暴露给模型。
  • 自动化运维助手:根据告警关键字动态选择日志查询、服务重启、健康检查等工具,避免把所有危险操作都暴露在同一个上下文中。
  • 个人助理:根据用户当前需求动态决定调用天气、日历、导航还是音乐播放工具。

这些场景有一个共同特征:工具数量多、任务类型分散、单次请求实际用到的工具很少。如果全部静态加载,效率和安全都不理想。

2. 环境准备与版本说明

2.1 运行环境

本文的示例代码使用 Python 编写,核心部分只依赖 Python 标准库,不需要安装额外第三方包,方便读者直接复制运行。

  • 操作系统:Windows / macOS / Linux 均可;
  • Python 版本:建议 3.9 及以上;
  • IDE:VS Code、PyCharm 均可,能运行 Python 脚本即可;
  • 可选依赖:如果后续要接入真实大模型,需要根据你使用的模型服务安装对应 SDK,版本以官方文档为准。

示例项目结构如下:

jit_agent/ ├── agent/ │ ├── __init__.py │ ├── registry.py │ ├── planner.py │ ├── executor.py │ └── runtime.py ├── tools/ │ ├── __init__.py │ ├── weather.py │ └── calculator.py └── main.py

agent包负责框架核心逻辑,tools包存放具体业务工具,main.py是入口。这样分层的好处是:框架与业务工具分离,新增工具不需要改动框架代码。

2.2 版本说明

关于 Python 版本,建议使用 3.9 以上,因为代码中用到了类型注解等特性,更低版本可能需要调整。如果你要在生产环境中接入真实大模型,版本需要根据你实际使用的模型服务调整,本文示例重点演示框架实现思路。

3. JIT 动态生成的核心原理拆解

3.1 从“静态 Agent”到“动态生成”

先看一个静态 Agent 的典型实现。

# 静态注册,启动时写死 def get_weather(city: str): return f"{city} 天气晴" def calculate(expression: str): return eval(expression) TOOLS = { "get_weather": get_weather, "calculate": calculate, }

这种方式在工具数量少时没有问题,但如果工具越来越多,问题就来了:

  • 每个请求都要把所有工具的描述拼进 Prompt;
  • 工具间如果有依赖关系,静态加载容易遗漏或冲突;
  • 新增工具需要修改TOOLS字典和 Prompt 模板。

JIT-Agent 的做法是引入“注册表 + 规划器”两层结构。注册表保存所有工具的元数据和执行函数,规划器在运行时根据用户输入决定加载哪些工具。核心思想是让“工具选择”变成动态过程。

3.2 工具注册表:动态生成的基础

注册表是 JIT-Agent 的地基。它维护一个全局字典,每个工具条目至少包含四个信息:工具名称、工具描述、参数 Schema、执行函数。名称用于唯一标识,描述用于给规划器做选择,参数 Schema 用于校验和生成调用参数,执行函数是真正运行的业务逻辑。

Python 中可以用装饰器实现一个极简注册表。

# agent/registry.py TOOL_REGISTRY = {} def register_tool(name, description, parameters_schema=None): def decorator(func): TOOL_REGISTRY[name] = { "name": name, "description": description, "parameters": parameters_schema or {}, "func": func, } return func return decorator def get_tool(name): return TOOL_REGISTRY.get(name) def list_tools(): return [ { "name": tool["name"], "description": tool["description"], "parameters": tool["parameters"], } for tool in TOOL_REGISTRY.values() ]

这里的关键点是:list_tools只返回元数据,不返回执行函数。这样在把工具列表发给大模型时,不会暴露内部实现。执行函数只在真正执行时才通过get_tool获取,这是动态生成的关键一步。

3.3 任务规划:动态选择工具的入口

注册表准备好了,剩下的问题是:怎么知道当前任务需要哪些工具?这就是“规划器”的职责。

规划器的输入是用户请求文本,输出是一个或多个“工具调用计划”,每个计划包含工具名和参数。最简单的方式是关键词匹配,适合演示;更通用的方式是调用大模型的 function calling 能力,让模型自己从工具列表中选择合适的工具。

不管是哪种方式,规划器的核心逻辑都一致:先用当前注册表中的工具元数据生成候选列表,再根据用户输入选择工具并提取参数。这就是“动态生成”的核心体现:工具列表不是固定的,而是随着请求变化。

4. 完整实战:手写一个轻量 JIT-Agent 框架

4.1 定义业务工具

先创建tools/weather.py,定义一个查询天气的工具。

# tools/weather.py from agent.registry import register_tool @register_tool( name="get_weather", description="查询指定城市的天气情况", parameters_schema={ "type": "object", "properties": { "city": {"type": "string", "description": "城市名称,例如:北京"} }, "required": ["city"], }, ) def get_weather(city: str) -> str: # 真实项目中可替换为天气 API 请求 return f"{city} 今天晴,气温 25 摄氏度,空气质量良。"

再创建tools/calculator.py,定义一个计算器工具。

# tools/calculator.py from agent.registry import register_tool @register_tool( name="calculate", description="计算简单的四则运算表达式", parameters_schema={ "type": "object", "properties": { "expression": {"type": "string", "description": "数学表达式,例如 3+5"} }, "required": ["expression"], }, ) def calculate(expression: str) -> str: # 演示代码直接使用 eval,生产环境请使用安全解析库 result = eval(expression) return f"{expression} = {result}"

到这里,工具定义已经完成。注意两个文件都通过@register_tool装饰器把函数注册到全局注册表,但主流程代码并没有直接引用它们。这意味着将来新增工具时,只需要新增一个文件并导入一次即可。

4.2 实现工具注册表

之前已经给出registry.py的代码,这里再补充一个细节:工具注册顺序会影响规划器看到的候选列表。实际项目中建议在入口文件统一导入所有工具模块,保证注册完成后再启动 Agent。

# agent/__init__.py

这个文件保持为空,用于标识agent是一个 Python 包。

4.3 实现任务规划器

接下来实现agent/planner.py。为了做到“零依赖即可运行”,演示版本用关键词匹配生成计划。

# agent/planner.py class Planner: def __init__(self, tools): self.tools = tools def plan(self, user_input: str) -> list: """ 根据用户输入生成执行计划。 演示版本使用关键词匹配,生产环境可替换为 LLM function calling。 """ plans = [] if "天气" in user_input: city = "北京" for candidate in ["北京", "上海", "广州", "深圳"]: if candidate in user_input: city = candidate break plans.append({"tool": "get_weather", "arguments": {"city": city}}) if "计算" in user_input or "算一下" in user_input: expression = user_input.replace("计算", "").replace("算一下", "").strip() plans.append({"tool": "calculate", "arguments": {"expression": expression}}) return plans

Planner接收tools参数,但在关键词匹配版本中没有直接使用。保留这个参数是为了后续替换成 LLM 规划器时,可以基于工具列表生成 function calling 请求。

如果用户输入同时包含“天气”和“计算”,比如“先看看北京天气,再计算 3+5”,规划器会生成两个计划,按顺序执行,这已经具备多步任务的雏形。

4.4 实现执行引擎

执行引擎负责真正调用工具函数。它从计划中取出工具名和参数,从注册表中获取执行函数,然后执行并返回结果。

# agent/executor.py from agent.registry import get_tool class Executor: def execute(self, plan: dict) -> str: tool_name = plan["tool"] tool = get_tool(tool_name) if not tool: return f"错误:工具 {tool_name} 未注册" try: result = tool["func"](**plan.get("arguments", {})) return result except Exception as e: return f"工具执行失败:{e}"

这里做了两层保护:第一层判断工具是否存在,第二层捕获执行异常。实际项目中还应该增加参数校验,确保调用参数符合工具的parameters_schema,避免恶意输入或异常参数传入工具函数。

4.5 实现运行时装配

运行时是整个 JIT-Agent 的入口,它把注册表、规划器、执行器组装在一起,对外提供run方法。

# agent/runtime.py from agent.registry import list_tools from agent.planner import Planner from agent.executor import Executor class JITAgent: def __init__(self): self.tools = list_tools() self.planner = Planner(self.tools) self.executor = Executor() def run(self, user_input: str): print(f"用户输入:{user_input}") print("当前可用工具:") for tool in self.tools: print(f" - {tool['name']}: {tool['description']}") plans = self.planner.plan(user_input) if not plans: return "没有找到合适的工具来处理该请求" outputs = [] for plan in plans: print(f"动态生成计划:{plan['tool']} {plan.get('arguments', {})}") result = self.executor.execute(plan) outputs.append(result) return "\n".join(outputs)

这个类体现了一个核心思想:JITAgent在初始化时只获取工具元数据,不直接绑定任何具体业务函数。每次运行请求时,规划器和执行器动态配合完成“选工具、调工具”的过程。

4.6 编写入口并运行验证

最后创建main.py,统一导入工具模块,然后启动 Agent。

# main.py from agent.runtime import JITAgent import tools.weather # noqa: F401 确保工具模块被导入并注册 import tools.calculator # noqa: F401 def main(): agent = JITAgent() print(agent.run("北京天气怎么样")) print("---") print(agent.run("计算 3+5")) if __name__ == "__main__": main()

在项目根目录运行:

python main.py

预期输出类似:

用户输入:北京天气怎么样 当前可用工具: - get_weather: 查询指定城市的天气情况 - calculate: 计算简单的四则运算表达式 动态生成计划:get_weather {'city': '北京'} 北京 今天晴,气温 25 摄氏度,空气质量良。 --- 用户输入:计算 3+5 当前可用工具: - get_weather: 查询指定城市的天气情况 - calculate: 计算简单的四则运算表达式 动态生成计划:calculate {'expression': '3+5'} 3+5 = 8

到这里,一个最简 JIT-Agent 已经可以运行。接下来可以思考如何把关键词规划器替换成真正的大模型规划器。

4.7 接入大模型 function calling 的改造思路

真实生产环境中,规划器应该让大模型来承担。以常见的 function calling 接口为例,改造思路如下。

# agent/llm_planner.py # 示例思路,需按实际模型服务调整 def plan_with_llm(user_input: str, tools: list) -> list: messages = [{"role": "user", "content": user_input}] functions = [ { "type": "function", "function": { "name": tool["name"], "description": tool["description"], "parameters": tool["parameters"], }, } for tool in tools ] # 调用你使用的模型服务,这里以伪代码示意 # response = chat_completion( # model="your-model", # messages=messages, # tools=functions, # ) # # 解析响应中的 tool_calls,转换为 plan 列表 # plans = [ # { # "tool": call.function.name, # "arguments": json.loads(call.function.arguments), # } # for call in response.choices[0].message.tool_calls # ] return []

核心点是:把list_tools()返回的元数据直接作为functions传给模型,模型返回工具调用计划后,执行引擎不用改动即可执行。这就是 JIT-Agent 最大的优势:工具不断新增,Agent 框架代码不变,模型每次都能看到最新的工具列表。

5. 常见问题与排查思路

下面列出 JIT-Agent 在实践中最常见的几类问题。

问题现象常见原因解决思路
工具未注册,执行时报错工具模块没有被导入在入口统一导入所有工具模块
大模型选错工具工具描述含糊、相似工具太多优化描述,增加示例,减少相似工具
参数解析报错function calling 返回的 JSON 格式不稳定增加 JSON 解析兜底,做参数 Schema 校验
上下文超长动态生成后仍然传入过多工具限制候选工具数量,分批选择
并发下状态混乱工具函数修改了全局状态工具函数尽量无状态,避免共享可变对象
动态加载延迟较高每次请求都重新分析任务增加缓存、预加载热工具

下面逐个展开说明。

工具未注册。这是使用注册表模式最容易踩的坑。register_tool装饰器在模块导入时执行,如果某个工具模块没有被 import,它的注册代码就不会运行。解决方法是把全部工具模块在main.py中统一导入,或使用importlib按目录自动加载。

大模型选错工具。工具列表是动态生成的,但如果工具描述写得含糊,模型仍然可能选错。比如get_weatherget_temperature功能相似,模型很难区分。建议在描述里写清楚边界,必要时在参数 Schema 的description中补充示例。

参数格式不稳。不同模型对 function calling 的响应格式有差异,有的模型返回的是 JSON 字符串,有的返回结构化对象。建议在规划器中增加统一解析层,解析失败时给模型一个“重新生成”的机会,而不是直接报错。

上下文超长。JIT-Agent 已经能减少无关工具,但工具数量特别多时,即使每个工具只描述一两行,全部传给模型也会撑爆上下文。可以按工具分组或先用模型做一次粗筛,再加载候选工具的详细描述。

并发状态混乱。如果工具函数操作了全局变量,多线程场景下容易出现互相覆盖。JIT-Agent 中工具函数应该尽量保持无状态,所有输入通过参数传入,输出通过返回值带出。

动态加载延迟。每次请求都动态分析确实会带来额外耗时。在延迟敏感的场景中,可以基于历史请求做热工具缓存,把高频工具提前加载到内存。

6. 最佳实践与工程建议

6.1 工具注册表的命名与版本管理

工具名称是全局唯一标识,建议用“动词 + 名词”的格式,例如query_ordercreate_ticketsend_email。避免使用模糊的do_taskrun之类名称。

工具数量增多后,还要考虑版本管理。可以在注册表条目中增加version字段,重要工具升级时保留旧版本,方便灰度切换。注册表本身可以增加enabled开关,让运营或开发临时下线有问题的工具,而不用重新发布代码。

6.2 配置与代码分离

JIT-Agent 的动态特性容易让人把业务逻辑写进框架代码里,这是需要避免的。工具列表、模型名称、超时时间、缓存策略等都应该放在配置文件中,通过配置中心或环境变量管理。这样工具上线、参数调整不需要改代码。

6.3 安全边界与权限控制

动态生成框架最大的风险是“工具暴露面变大”。如果所有工具都注册到一个全局注册表,一旦规划器被诱导,就可能调用危险工具。因此需要做到以下几点:

  • 工具函数内部做输入校验,不轻信规划器传来的参数;
  • 高危操作需要二次确认,比如删除资源、发起支付;
  • 不要在生产环境使用evalexec,计算器示例只是为了演示原理;
  • 对大模型的工具选择结果做白名单校验,只允许调用当前任务允许范围内的工具;
  • 对用户输入做提示注入防护,避免用户通过自然语言诱导模型调用未授权工具。

6.4 日志与可观测性

动态生成意味着每次请求的行为都可能不同,必须把规划结果记录下来。建议至少记录以下内容:

  • 用户原始输入;
  • 本次请求加载了哪些工具;
  • 规划器生成的工具调用计划;
  • 每个工具的执行结果和执行耗时;
  • 如果规划器调用大模型,记录模型返回的原始响应。

有了这些日志,才能快速定位“模型选错工具”“参数错误”“工具执行异常”等问题。

6.5 性能优化

动态生成虽然灵活,但性能也需要关注。常见优化手段包括:

  • 工具元数据缓存,避免每次请求都重新遍历注册表;
  • 热工具预加载,把高频工具的执行函数提前放入内存;
  • 规划结果缓存,对于相同或相似请求,直接复用之前的工具调用计划;
  • 并发控制,避免大量请求同时触发大模型规划,导致上游服务超时。

6.6 生产环境注意事项

上线前建议先做一次“全量工具扫描”,确保所有工具模块都能正常导入、注册、执行。还要准备一个“最小工具集”兜底:当规划器没有返回任何计划,或返回的工具全部执行失败时,Agent 应该能给用户一个明确回复,而不是静默失败。

如果使用真实大模型规划器,要关注模型服务的限流和成本。可以给每次任务的规划调用设置超时时间,并在超时后降级到关键词规划器,保证核心链路可用。

7. 总结与学习路线

这篇文章主要围绕 JIT-Agent 展开,核心内容可以总结为三点:第一,JIT-Agent 是一种动态生成智能体框架的设计模型,核心是把工具选择和流程组装推迟到运行时;第二,实现一个轻量 JIT-Agent 的关键是注册表加规划器,注册表负责管理工具元数据,规划器负责按任务选择工具;第三,动态生成框架在灵活性上优于静态注册,但同时要关注安全、日志、性能和可观测性。

如果你对智能体框架感兴趣,下一步可以继续学习三块内容:一是 ReAct 模式,搞清楚 Agent 如何在大模型推理和工具调用之间循环;二是多 Agent 协作,了解多个 JIT-Agent 如何分工配合;三是工具自治,让 Agent 在运行时自动生成工具描述,甚至动态生成新的工具函数。无论走哪个方向,都可以先把本文这套最小框架跑通,再逐步往里面加入真实模型、持久化存储和更完善的工具管理能力。

实际项目中优先关注的风险点有两个:一个是工具暴露面变大带来的安全风险,另一个是动态生成导致的可观测性变差。只要把注册表权限控制和日志链路做好,JIT-Agent 就能在日常业务中发挥很大的灵活性。

如果你正在设计自己的 Agent 框架,不妨从一个小场景开始,把一两个工具接入动态注册表,跑通后再逐步扩展。如果这篇文章对你有帮助,可以收藏备用,也欢迎在评论区交流你在动态生成 Agent 时踩过的坑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/30 5:49:04

LangChain、LangGraph、Deep Agents与ADK:四大Agent框架对比与选型指南

最近 Agent 这个概念又热了一轮,网上框架多到让人头疼:LangChain 是老牌选择,LangGraph 主打图编排,Deep Agents 靠 OpenAI 生态吸了一波关注,ADK 又是 Google 官方推出的开发套件。很多做 RAG、工具调用、多智能体编排…

作者头像 李华
网站建设 2026/8/30 5:48:52

从零搭建渐进式AI应用:Stone Soup AI工程实践指南

Stone Soup AI 是 2024 年 AI 工程实践里一个很有意思的项目代号,它借了“石头汤”这个寓言的壳:一锅汤开始只放一块石头和水,路过的人各自加入一点食材,最后煮成一锅所有人都能分享的浓汤。放到 AI 应用开发里,这条思…

作者头像 李华
网站建设 2026/8/30 5:47:02

世界模型的新台阶:心智世界建模让AI理解他人意图

现在大家都在讨论世界模型,但很多讨论把它默认为“物理世界的模拟器”——预测物体的位置、学习环境变换规律、让智能体在脑海里预演动作。这个理解没有错,却漏掉了一个更值得关注的转向。牛津、NUS 团队提出的“心智世界建模”(Mental World…

作者头像 李华
网站建设 2026/8/30 5:46:46

ComfyUI+ControlNet涂鸦引导图生图:从草图到插画的完整工作流

简介:本资源是一套面向ComfyUI初学者与AIGC图像生成实践者的ControlNet涂鸦引导图生图工作流配置方案,专为SD1.5模型环境设计,解决手绘草图精准控制生成内容结构与构图的核心需求。压缩包仅含1个3KB的JSON文件,为ComfyUI可直接导入…

作者头像 李华
网站建设 2026/8/30 5:46:45

六大查重系统一站式对接值不值?5维度拆解

围绕"一站式对接六大查重系统到底值不值"这个问题,我们沿着覆盖度、官方性、效率、完整性、口径一致性五个维度做了拆解。结论先说:对需要在多个系统间反复切换、又想和学校终检口径对齐的同学,一站式官方通道对接能明显省事。以知…

作者头像 李华