☰
AI Agent开发碎片化破局:GitAgent声明式配置与工程化实践
2026/9/25 17:30:49 网站建设 项目流程

1. AI Agent开发的碎片化困局到底卡在哪

做过AI Agent项目的人大概都有这种体会:明明只是想做一个能自动处理工单、能查数据库、能调API的小助手,结果光是项目结构就折腾了一整天。工具调用逻辑写在一个文件里,提示词模板散落在另一个目录,记忆管理又是第三套代码,状态机、回调、日志、测试各占一块地盘。等到想换一个模型供应商,发现耦合得太深,改一处崩三处。这种“碎片化”不是某一个人的问题,而是整个AI Agent开发领域在快速膨胀期必然经历的阵痛。

我最早接触Agent开发是在做一些自动化运维的脚本编排,那时候还没有“Agent”这个时髦词,大家管它叫“智能工作流”。后来大模型能力上来了,工具调用、多轮推理、记忆检索这些能力被塞进同一个项目里,代码量从几百行暴涨到几千行,团队协作开始出现明显的摩擦。一个新同事加入,光是搞清楚“这个请求从入口到最终回复经过了哪些模块”就要花两三天。更麻烦的是,不同项目之间的Agent代码几乎无法复用,每个项目都在重复造轮子,而且造出来的轮子规格还不一样。

GitAgent这个概念之所以引起讨论,是因为它试图回答一个很朴素的问题:既然Docker用镜像和容器解决了环境一致性和应用分发的问题,那AI Agent能不能也用类似的方式,把“一个Agent”变成一个可打包、可分发、可复现的单元?这个思路听起来很自然,但落地起来涉及的问题远比想象中复杂。Docker解决的是进程隔离和文件系统分层,而Agent涉及的是提示词、工具集、记忆策略、模型配置、运行时状态等一系列更“软”的东西。这些东西能不能像Dockerfile那样被声明式地描述出来,是GitAgent这类方案要面对的核心挑战。

这篇文章我想从实际开发的角度,把AI Agent碎片化的几个典型症状拆开来看,然后讨论GitAgent这类方案在哪些环节能帮上忙、哪些环节还需要自己补位。如果你正在做Agent相关的项目,或者正准备从零搭一个Agent框架,这些经验应该能帮你少走一些弯路。文章会涉及项目结构设计、工具注册机制、记忆管理、模型抽象层、打包分发这几个关键环节,每个环节我都会给出具体的做法和踩过的坑。

提示:本文讨论的“GitAgent”指的是一类以Git仓库为分发载体、以声明式配置描述Agent行为的方案思路,不特指某一个具体产品。不同团队可能有不同的实现,但核心逻辑是相通的。

2. 拆解Agent项目的碎片化症状与根因

2.1 症状一:项目结构没有共识,每个项目都是一次重新发明

我见过太多Agent项目的目录结构是这样的:根目录下散落着main.py、agent.py、tools.py、prompts/、memory.py、config.yaml,再往深了看,tools.py里面既有工具定义又有工具调用逻辑还有错误处理,agent.py里面既有状态管理又有模型调用还有输出解析。这种结构在项目初期跑得通,但一旦要加第二个Agent、要支持多模型、要接入外部记忆存储,就会迅速变成一团乱麻。

根因在于,Agent开发目前没有像Web开发那样形成成熟的目录规范。做Web开发的人都知道models/、views/、controllers/该怎么分,但Agent开发里“一个工具”应该放在哪、“一段提示词”应该怎么组织、“记忆”应该由谁负责读写,这些问题没有标准答案。每个人凭直觉放,最后就是每个人都有自己的直觉。

我的做法是强制自己遵循一套最小结构约定,不管项目多小都保持一致。这套约定大概是这样:

  • agents/目录:每个Agent一个子目录,里面放这个Agent的配置文件、专属提示词、专属工具
  • tools/目录:跨Agent共享的工具,按功能域再分子目录,比如tools/db/、tools/http/
  • memory/目录:记忆存储的读写接口和具体实现,接口和实现分离
  • runtime/目录:Agent的运行循环、状态机、回调钩子
  • configs/目录:模型配置、环境配置、密钥管理(密钥走环境变量,不落盘)

这套结构的好处是,当你要新增一个Agent时,你很清楚该在哪里建目录、该在哪里注册工具、该在哪里写提示词。它不完美,但至少让团队有了共同语言。

2.2 症状二:工具注册靠硬编码,复用基本靠复制粘贴

工具调用是Agent的核心能力之一。但很多项目里,工具的注册方式是直接在代码里写死一个列表:

tools = [ {"name": "query_order", "func": query_order, "description": "..."}, {"name": "send_email", "func": send_email, "description": "..."}, ]

这种写法的问题在于,工具和Agent绑死了。你想让另一个Agent也用query_order,只能把这段代码复制过去。更糟糕的是,当工具数量增长到几十个时,这个列表会变得难以维护,而且模型在选择工具时也会因为描述不够精确而频繁选错。

我后来改成用装饰器加注册表的方式:

from registry import tool_registry @tool_registry.register( name="query_order", description="根据订单号查询订单状态,输入为订单号字符串", parameters={"order_id": {"type": "string", "required": True}} ) def query_order(order_id: str) -> dict: ...

这样工具的定义和注册在一起,Agent只需要声明自己需要哪些工具(按名称引用),运行时从注册表里取。工具的实现和Agent的配置解耦了,复用就是改一行配置的事。

但这里有个坑:工具的description和parameters描述直接决定了模型能不能正确调用。我踩过的坑是描述写得太笼统,比如“查询订单”,模型不知道输入格式是什么,经常传一个JSON对象进来而不是字符串。后来我强制要求每个工具的description必须包含三要素:做什么、输入是什么格式、输出是什么结构。这个习惯养成之后,工具调用的准确率明显提升。

2.3 症状三:记忆管理各自为政,上下文窗口永远不够用

Agent的“记忆”是个被低估的复杂问题。短期记忆(当前对话的上下文)、长期记忆(跨会话的知识)、工作记忆(当前任务相关的临时信息)这三层记忆的管理策略完全不同,但很多项目把它们混在一起,全部塞进上下文窗口,结果就是token消耗飞快,而且模型容易被无关信息干扰。

我见过一个项目,把用户过去三十天的所有对话记录都拼进prompt里,美其名曰“全量记忆”。结果每次请求的token数都在爆炸边缘,响应慢不说,模型还经常“跑偏”,因为历史信息里有很多和当前问题无关的内容。

合理的做法是分层管理。短期记忆就是当前会话的消息列表,这个没什么好说的,按轮次保留即可。长期记忆需要做检索,通常是向量化之后存向量库,每次根据当前问题检索最相关的几条。工作记忆是任务级的,比如当前在处理一个退款流程,那么退款相关的订单信息、用户信息、政策条款应该放在工作记忆里,任务结束后清掉。

这里的关键是,记忆的读写应该由统一的接口来管,而不是让每个工具自己往上下文里塞东西。我的做法是定义一个MemoryManager,所有记忆的写入和读取都走它,Agent的运行时循环在每一轮开始前向MemoryManager请求“当前应该注入哪些记忆”,而不是自己拼上下文。

2.4 症状四:模型抽象层缺失,换模型等于重写

模型供应商的迭代速度太快了。今天用A模型效果最好,明天B模型出了新版本性价比更高,后天C模型支持了更长的上下文。如果代码里到处是client.chat.completions.create(...)这样的调用,换模型就是一场灾难。

我坚持的做法是加一层薄薄的模型抽象层。这层抽象不需要做太多事,核心就是统一输入输出格式:

class ModelAdapter: def chat(self, messages: list, tools: list = None, **kwargs) -> ModelResponse: ...

不同的模型供应商各写一个Adapter,把各自的API调用封装进去,对外暴露统一的chat接口。Agent的运行时只依赖这个接口,不依赖任何具体供应商的SDK。这样换模型只需要换一个Adapter,Agent的逻辑一行不用改。

这层抽象还有一个好处:方便做A/B测试。你可以同时挂两个Adapter,把同一个请求发给两个模型,对比输出质量。我在做提示词优化时经常这么干,效果很直观。

3. GitAgent思路能解决什么,不能解决什么

3.1 GitAgent的核心思路:把Agent变成可版本化的声明式单元

GitAgent这个概念最吸引人的地方在于,它试图把Agent的定义从“一堆代码”变成“一份声明”。就像Dockerfile描述了一个镜像应该包含什么,GitAgent试图用一份配置文件描述一个Agent应该包含什么:用哪个模型、挂哪些工具、提示词是什么、记忆策略是什么、运行时参数是什么。

这份声明放在Git仓库里,天然获得了版本控制、分支管理、代码审查、CI/CD这些能力。你要分发一个Agent,就是分享一个仓库地址;你要复现一个Agent的行为,就是checkout到某个commit;你要改一个Agent的行为,就是提一个PR。这些在传统软件开发里稀松平常的操作,在Agent开发里却因为缺乏统一的描述方式而变得困难。

我试过用类似思路管理自己的Agent项目:每个Agent一个目录,目录里有一个agent.yaml描述这个Agent的配置,有一个prompts/目录放提示词模板,有一个tools.yaml声明依赖哪些工具。运行时读取这些配置,动态组装出一个Agent实例。这样做之后,新增一个Agent的成本从“写几百行代码”变成了“写几十行配置”,而且配置的diff非常清晰,review起来很快。

3.2 能解决的:环境一致性、版本追溯、分发复用

GitAgent思路最能帮上忙的场景是团队协作和跨项目复用。当Agent的定义被声明式地描述之后,环境一致性就有了保障。新同事拉下仓库,按照README装好依赖,运行起来的行为和你的机器上应该是一致的(前提是模型版本和工具依赖也锁定了)。

版本追溯也变得简单。某个Agent上周的表现很好,这周改了一版提示词之后效果下降了,直接diff一下提示词文件就能看出改了什么,回滚就是一次revert。这在没有声明式描述的项目里,往往需要翻聊天记录、翻代码提交历史,还不一定找得到。

分发复用是另一个明显收益。你写了一个“客服工单分类Agent”,同事的项目里也需要类似能力,他不需要复制你的代码,只需要在你的仓库基础上改配置、换提示词、挂自己的工具。这种复用粒度比代码级复用更粗,但比复制粘贴更可控。

3.3 不能解决的:运行时状态、外部依赖、模型行为差异

但GitAgent不是银弹。它解决的是“定义”层面的问题,解决不了“运行时”层面的问题。Agent在运行过程中产生的状态——当前会话的上下文、工作记忆里的临时数据、工具调用的中间结果——这些是动态的,没法用声明式配置描述,也不应该被版本控制。

外部依赖也是个大问题。你的Agent依赖一个数据库、一个消息队列、一个外部API,这些依赖的可用性和版本不在GitAgent的控制范围内。Docker通过容器化解决了运行时依赖的隔离,但Agent的外部依赖往往是有状态的、网络化的服务,没法简单打包进容器。

最棘手的是模型行为差异。同一个提示词,同一个模型的不同版本,输出可能完全不同。你锁定了配置里的模型名称,但供应商在后台更新了模型权重,你的Agent行为就变了。这个问题目前没有完美的解法,只能通过持续评测来监控。我的做法是给每个Agent配一套回归测试用例,每次模型供应商发新版本时跑一遍,看关键指标有没有明显波动。

3.4 和Docker的类比:像,但别指望完全一样

把GitAgent比作“Agent领域的Docker”是个很好的传播话术,但实际落地时别指望它能达到Docker那样的隔离性和可移植性。Docker镜像里包含了一个完整的文件系统,走到哪都能跑出一样的结果。Agent的“镜像”里只有配置和代码,运行时依赖外部模型服务、外部工具服务,这些服务的差异会直接反映到Agent行为上。

更准确的类比可能是“Agent领域的npm/pip”:它提供了一种声明依赖和分发单元的方式,但运行时的环境仍然需要你自己保证。这个定位其实已经很有价值了,因为Agent开发目前最缺的就是这种“声明依赖、一键组装”的基础设施。

4. 从零搭建一个可复用的Agent项目结构

4.1 目录结构设计:让每个文件都有明确归属

基于前面的讨论,我把自己在用的目录结构整理如下。这套结构不依赖任何特定框架,你可以直接拿去用,也可以根据自己的习惯调整。

project/ ├── agents/ │ ├── customer_service/ │ │ ├── agent.yaml │ │ ├── prompts/ │ │ │ ├── system.md │ │ │ └── few_shot.md │ │ └── tools.yaml │ └── data_analyst/ │ ├── agent.yaml │ ├── prompts/ │ └── tools.yaml ├── tools/ │ ├── db/ │ │ ├── query_order.py │ │ └── query_user.py │ └── http/ │ └── call_external_api.py ├── memory/ │ ├── interface.py │ ├── short_term.py │ └── long_term.py ├── runtime/ │ ├── loop.py │ ├── state.py │ └── hooks.py ├── configs/ │ ├── models.yaml │ └── env.yaml └── tests/ ├── test_customer_service.py └── fixtures/

这个结构的关键在于职责分离。agents/下面每个子目录是一个独立的Agent定义,包含它的配置、提示词、工具依赖声明。tools/下面是工具的实现,按功能域分组。memory/下面是记忆管理的接口和实现。runtime/下面是Agent的运行循环和状态管理。configs/下面是全局配置。tests/下面是测试。

4.2 Agent配置文件怎么写:一份可读的agent.yaml

agent.yaml是Agent的核心描述文件。我用的格式大概是这样:

name: customer_service version: 1.0.0 model: provider: openai name: gpt-4o temperature: 0.3 max_tokens: 2000 prompts: system: prompts/system.md few_shot: prompts/few_shot.md tools: - query_order - query_user - send_email memory: short_term: max_turns: 20 long_term: enabled: true retrieval_top_k: 5 runtime: max_iterations: 10 timeout_seconds: 60

这份配置里,model段描述用哪个模型、什么参数;prompts段指向提示词文件;tools段列出依赖的工具名称;memory段描述记忆策略;runtime段描述运行时的限制。

这样做的好处是,Agent的行为完全由这份配置和它引用的文件决定。你要改模型参数,改配置;要改提示词,改提示词文件;要加工具,改tools列表。所有改动都是可diff、可review、可回滚的。

4.3 工具注册与发现:让工具自己“报到”

工具的实现放在tools/目录下,每个工具文件里用装饰器注册自己。运行时启动时,扫描tools/目录,自动导入所有工具模块,触发注册。

# tools/db/query_order.py from registry import tool_registry @tool_registry.register( name="query_order", description="根据订单号查询订单状态。输入为订单号字符串,输出为包含状态、金额、时间的字典。", parameters={ "order_id": { "type": "string", "description": "订单号,格式为ORD开头加12位数字", "required": True } } ) def query_order(order_id: str) -> dict: # 实际查询逻辑 return {"status": "paid", "amount": 99.0, "created_at": "..."}

这种自动发现机制的好处是,新增工具不需要改任何注册代码,只需要在tools/下新建文件。Agent的tools.yaml里引用工具名称即可。工具的实现和Agent的配置彻底解耦。

注意:自动发现机制要小心循环导入和导入副作用。我的做法是工具模块里只做注册,不做任何实际执行逻辑,实际执行逻辑放在被注册的函数里,只有被调用时才执行。

4.4 记忆管理的分层实现:短期、长期、工作记忆各司其职

记忆管理的接口定义在memory/interface.py:

class MemoryManager: def get_context(self, session_id: str, query: str) -> list: """返回当前应该注入上下文的记忆列表""" ... def add_message(self, session_id: str, message: dict): """添加一条消息到短期记忆""" ... def add_knowledge(self, session_id: str, knowledge: str): """添加一条知识到长期记忆""" ...

短期记忆用简单的列表实现,按会话ID隔离,超过max_turns就丢弃最旧的消息。长期记忆用向量库实现,写入时做embedding,读取时按相似度检索。工作记忆用一个字典实现,任务开始时创建,任务结束时销毁。

运行时循环在每一轮开始前调用get_context,拿到应该注入的记忆,拼进prompt。这样Agent的逻辑不需要关心记忆是怎么存的、怎么取的,只需要关心“当前应该看到什么”。

5. 实操:把一个碎片化Agent改造成可分发单元

5.1 改造前的项目状态评估

假设你手上有一个已经能跑的Agent项目,但结构比较乱。改造的第一步是评估现状。我通常会问自己几个问题:

  • 这个Agent依赖哪些工具?这些工具的实现散落在哪些文件里?
  • 提示词写在哪里?是硬编码在代码里还是放在单独文件里?
  • 模型调用散落在哪些地方?有没有统一的入口?
  • 记忆管理是怎么做的?有没有统一的接口?
  • 如果要让另一个项目复用这个Agent,需要复制哪些文件?

把这些问题回答清楚,改造的范围就明确了。通常来说,最需要优先处理的是模型调用和工具注册,因为这两块的耦合度最高,改造收益也最大。

5.2 第一步:抽出模型抽象层

找到所有直接调用模型SDK的地方,把它们替换成对ModelAdapter的调用。Adapter的实现可以很简单:

class OpenAIAdapter(ModelAdapter): def __init__(self, config): self.client = OpenAI(api_key=config["api_key"]) self.model = config["model"] def chat(self, messages, tools=None, **kwargs): response = self.client.chat.completions.create( model=self.model, messages=messages, tools=tools, **kwargs ) return ModelResponse( content=response.choices[0].message.content, tool_calls=response.choices[0].message.tool_calls, usage=response.usage )

这一步的改造量取决于原来代码的混乱程度。如果模型调用散落在十几个文件里,可能需要花半天到一天。但这一步做完之后,换模型、做A/B测试、加缓存都会变得非常方便。

5.3 第二步:工具注册表改造

把散落的工具定义收集起来,统一用装饰器注册。这一步的关键是给每个工具写清楚description和parameters。我通常会花不少时间在这上面,因为工具描述的质量直接决定模型调用的准确率。

一个实用的技巧是,在写description时想象你在给一个新人解释这个工具:它做什么、什么时候用、输入什么、输出什么、有什么限制。把这些都写清楚,模型选错工具的概率会大幅下降。

改造完成后,Agent的配置里只需要列出工具名称,运行时从注册表取。新增工具不需要改Agent代码,只需要在tools/下新建文件并在配置里引用。

5.4 第三步:提示词外置与版本化

把硬编码在代码里的提示词抽出来,放到prompts/目录下的Markdown文件里。这样做的好处是提示词的修改不需要改代码,非技术人员也能参与优化,而且diff非常清晰。

我习惯把提示词分成system.md和few_shot.md两个文件。system.md放系统提示词,定义Agent的角色、能力边界、输出格式要求。few_shot.md放少样本示例,帮助模型理解期望的输入输出模式。两个文件分开的好处是,调整示例不会影响系统提示词,反之亦然。

提示词文件纳入Git管理,每次修改都有记录。我还会在提示词文件头部加一个版本注释,记录修改日期和修改原因,方便回溯。

5.5 第四步:打包与分发

改造完成后,这个Agent目录就可以作为一个独立单元分发了。分发的方式很简单:把agents/customer_service/目录连同它依赖的tools/、memory/、runtime/一起打包成一个Git仓库,或者作为一个子目录放在现有仓库里。

接收方拿到之后,按照README装好依赖,配置好模型密钥,运行启动脚本即可。如果接收方需要定制,改agent.yaml和提示词文件即可,不需要动核心代码。

这种分发方式的粒度比Docker镜像粗,但比复制粘贴代码可控得多。它不保证运行时环境的完全一致,但保证了Agent定义的一致性和可追溯性。

6. 常见问题与排查技巧实录

6.1 工具调用频繁失败怎么办

工具调用失败通常有三个原因:工具描述不清晰、参数格式不匹配、工具本身报错。排查顺序建议从描述开始。

先检查工具的description是否包含了“做什么、输入格式、输出格式”三要素。如果描述太笼统,模型很容易传错参数。我遇到过一个案例,工具描述写的是“查询用户信息”,模型有时候传用户ID,有时候传用户名,有时候传一个JSON对象。后来把描述改成“根据用户ID查询用户信息,输入为字符串类型的用户ID,输出为包含姓名、邮箱、注册时间的字典”,调用准确率从六成提升到九成以上。

如果描述没问题,检查参数定义是否和实际函数签名一致。我见过参数定义里写required: True但函数签名里有默认值的情况,模型会困惑到底要不要传这个参数。

最后检查工具本身的错误处理。工具执行报错时,应该返回一个结构化的错误信息,而不是直接抛异常。模型看到错误信息后可以决定是重试还是换一个工具。

6.2 上下文窗口不够用怎么优化

上下文窗口不够用是Agent开发的常态。优化手段按优先级排序:

第一,检查是否有无关信息被塞进了上下文。比如把整个对话历史都拼进去,但其中很多轮次和当前问题无关。短期记忆应该只保留最近N轮,N的取值根据任务复杂度调整,一般10到20轮够用。

第二,长期记忆的检索要精准。检索top_k不要设太大,3到5条通常足够。检索的相似度阈值要调,太低会引入无关信息,太高会漏掉有用信息。我一般会先用一批测试问题跑一遍,看检索结果的相关性,再定阈值。

第三,提示词要精简。系统提示词里不要写太多示例,示例放在few_shot里按需注入。输出格式要求尽量用简洁的schema描述,不要用大段自然语言。

第四,考虑用支持更长上下文的模型。但这应该是最后的手段,因为长上下文意味着更高的成本和更慢的响应。

6.3 模型换版本后行为变了怎么排查

模型供应商更新版本导致Agent行为变化,这个问题很难完全避免,但可以通过建立回归测试来快速发现和定位。

我的做法是给每个Agent维护一套测试用例,覆盖核心场景。每个用例包含输入和期望的输出特征(不要求完全匹配,但要求关键信息正确)。每次模型版本更新后,跑一遍测试,看通过率有没有明显下降。

如果发现行为变化,先对比新旧版本在相同输入下的输出差异。有时候只是输出格式变了,调整一下输出解析逻辑即可。有时候是推理能力变了,可能需要调整提示词。极少数情况下是模型能力退化,那就只能回滚到旧版本或者换模型。

提示:回归测试用例不需要很多,每个Agent有10到20个核心场景就够了。关键是这些场景要覆盖Agent的主要能力,而且期望输出要足够具体,能区分“正确”和“错误”。

6.4 多Agent协作时的状态同步问题

当多个Agent需要协作完成一个任务时,状态同步是个容易出问题的地方。我踩过的坑是,两个Agent各自维护自己的记忆,结果一个Agent做了决策,另一个Agent不知道,导致重复操作或冲突。

解决思路是引入一个共享的工作记忆层。所有Agent的工作记忆都读写同一个存储,键用任务ID隔离。每个Agent在做出会影响其他Agent的决策时,先写入工作记忆,其他Agent在行动前先读取工作记忆。

这个共享层的实现可以很简单,一个带锁的字典就行。关键是约定好键的命名规范和写入时机。我一般要求Agent在“做出决策”和“执行完动作”两个时间点写入工作记忆,其他Agent在“开始新一轮推理”时读取。

6.5 常见问题速查表

问题现象可能原因排查方向解决建议
工具调用参数错误工具描述不清晰检查description三要素补充输入格式和示例
上下文超限记忆注入过多检查短期记忆轮数和长期检索top_k减少轮数,调高相似度阈值
模型输出格式不稳定提示词约束不够检查输出格式描述用schema替代自然语言描述
换模型后效果下降模型行为差异跑回归测试对比调整提示词或回滚模型
多Agent状态冲突缺少共享状态层检查各Agent记忆是否隔离引入共享工作记忆
工具执行超时外部依赖慢检查工具内部调用链加超时和重试机制

7. 我对Agent工程化的一些个人体会

做Agent开发这两年,我最大的体会是:这个领域的技术迭代很快,但工程化的基本功没有变。目录结构、配置管理、接口抽象、版本控制、测试覆盖,这些在传统软件开发里被反复强调的东西,在Agent开发里同样重要,甚至更重要,因为Agent的行为更不确定,更需要通过工程手段来约束和观测。

GitAgent这类思路的价值不在于它提供了什么黑科技,而在于它把“声明式定义、版本化管理、可分发复用”这些成熟的工程实践引入了Agent开发。它不会解决所有问题,但能让Agent项目从“一次性脚本”变成“可维护的软件资产”。

如果你正在做Agent项目,我的建议是尽早把项目结构规范化,哪怕一开始只有一个人开发。因为Agent项目的复杂度增长是非线性的,等到代码量上来之后再重构,成本会高很多。先从模型抽象层和工具注册表开始,这两块的改造收益最明显。提示词外置和记忆分层可以稍后做,但目录结构最好一开始就定好。

最后分享一个小技巧:给每个Agent写一个README,说明它的能力边界、依赖项、配置方式、测试方法。这个README不需要很长,但能帮你在几个月后重新打开这个项目时快速回忆起它是干什么的。我吃过这个亏,半年前写的一个Agent,半年后完全想不起来当时为什么那么设计,翻代码翻了半天才理清楚。从那以后,每个Agent目录下必放一个README。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询