@codebuff/sdk 开发指南:用 TypeScript 构建 AI Coding Agent 与自定义工具

发布时间:2026/9/15 14:22:40

@codebuff/sdk 开发指南:用 TypeScript 构建 AI Coding Agent 与自定义工具 codebuff/sdk 开发指南用 TypeScript 构建 AI Coding Agent 与自定义工具【免费下载链接】freebuffThe free coding agent项目地址: https://gitcode.com/GitHub_Trending/cod/freebuff导读本指南基于开源仓库GitHub_Trending/cod/freebuff中sdk/目录的官方 README 与源码系统讲解codebuff/sdk的安装、初始化、运行 Agent、延续会话、自定义 Agent 与自定义工具、知识文件注入、文件过滤安全策略以及本地 Agent 加载等核心能力。读完本文你将掌握如何在 Node.js / Bun / TypeScript 项目中通过几行代码驱动 Codebuff 的 AI 编码代理并将自己的业务逻辑封装为可被 LLM 调用的自定义工具。一、SDK 是什么从 README 到源码入口codebuff/sdk是 CodebuffAI 编码 Agent 与框架的官方 SDK定位为以编程方式运行 Codebuff 代理的客户端库。它的 TypeScript 类型、客户端类与所有公共 API 都在仓库 sdk/src/index.ts 中统一导出主要包括CodebuffClientSDK 的入口类负责持有 API Key、工作目录等客户端级配置client.run(options)运行一次 Agent 交互对应源码 sdk/src/client.ts 中的run方法getCustomToolDefinition自定义工具工厂函数sdk/src/custom-tool.tsloadLocalAgents从.agents目录加载 Agent 定义sdk/src/agents/load-agents.ts以及loadMCPConfig、loadSkills、validateAgents、getFileTokenScores等一系列进阶能力。从仓库根目录的依赖关系看sdk依赖common、agent-runtime、code-map、llm-providers等内部包见 sdk/package.json其中zodv4负责自定义工具的输入校验tree-sitter/code-map 负责对项目文件做符号级 token 评分以挑选上下文文件。二、安装与前置条件1. 安装在任意 Node.js 项目中使用以下命令安装npm install codebuff/sdk从 sdk/package.json 可以看到该包的运行环境要求Node.js 22.0.0包本身以 ESM 为主type: module同时通过exports字段同时提供.mjsimport与.cjsrequire两种构建产物当前仓库内 SDK 版本为0.10.7engines声明即为当前仓库的实际约束。2. 准备 API Key使用 SDK 前需要注册 Codebuff 账号在 Codebuff 网站的个人资料页的 API Keys 标签页创建 API Key。API Key 有两种注入方式显式传入new CodebuffClient({ apiKey: ... })环境变量不传apiKey时CodebuffClient构造函数会自动尝试从环境变量读取。在源码 sdk/src/client.ts 中可以看到其回退逻辑const foundApiKey options.apiKey ?? getCodebuffApiKeyFromEnv() if (!foundApiKey !options.byok) { throw new Error( Codebuff API key not found. Please provide an apiKey in the constructor of CodebuffClient or set the ${API_KEY_ENV_VAR} environment variable., ) }即既没有显式 API Key、也没有使用 BYOK自带模型密钥时构造会直接抛出异常。因此最简单的启动方式是export CODEBUFF_API_KEYyour_api_key_here三、快速上手运行第一个 Agent1. 基础示例新建一个 TypeScript 文件如main.ts写入import { CodebuffClient } from codebuff/sdk async function main() { const client new CodebuffClient({ // 传入你自己的 API Key也可以依赖 CODEBUFF_API_KEY 环境变量 apiKey: process.env.CODEBUFF_API_KEY, cwd: process.cwd(), }) // 第一次运行 const runState1 await client.run({ // Agent id可以是官方 Store 中的任意 Agent agent: codebuff/base0.0.16, prompt: Create a simple calculator class, handleEvent: (event) { // 运行期间的所有事件agent 开始/结束、工具调用/结果、文本回复、错误等 console.log(Codebuff Event, JSON.stringify(event)) }, }) // 用 previousRun 延续同一个会话进行追问 const runOrError2 await client.run({ agent: codebuff/base0.0.16, prompt: Add unit tests for the calculator, previousRun: runState1, // -- 与第一次运行的关键区别 handleEvent: (event) { console.log(Codebuff Event, JSON.stringify(event)) }, }) } main()这个示例对应仓库中的可运行样例 sdk/examples/readme-example-1.ts结构与 README 完全一致。2. 关键点拆解cwdAgent 运行的工作目录决定它读写文件、执行终端命令的项目范围不传时以当前进程目录为准。handleEvent实时事件回调。SDK 会不断推送PrintModeEvent类型定义见 sdk/src/run.ts你可以用它把 Agent 的进度流式渲染到自己的 UI。previousRun会话延续的关键参数。run()返回的RunState对象中携带了内部sessionState将其回传给下一次run()即可保持对话上下文——这正是多轮交互、逐步实现复杂任务的基础。四、自定义 Agent 与自定义工具把业务能力交给 LLMSDK 最强大的能力是自定义。你可以定义专属 Agent 的行为模型、指令、可用工具并为它编写可被 LLM 按需调用的自定义工具。1. 完整示例import { z } from zod/v4 import { CodebuffClient, getCustomToolDefinition } from codebuff/sdk import type { AgentDefinition } from codebuff/sdk async function main() { const client new CodebuffClient({ // 注意需要传入你自己的 API Key apiKey: process.env.CODEBUFF_API_KEY, // Agent 运行的工作目录可选 cwd: process.cwd(), }) // 定义你自己的自定义 Agent const myCustomAgent: AgentDefinition { id: my-custom-agent, model: google/gemini-3.1-flash-lite, displayName: Sentiment analyzer, toolNames: [fetch_api_data], // 指定该 Agent 可用的工具见下 instructionsPrompt: 1. Describe the different sentiments in the given prompt. 2. Score the prompt along the following 5 dimensions: happiness, sadness, anger, fear, and surprise., // ... 其他 AgentDefinition 属性 } // 定义你自己的自定义工具 const myCustomTool getCustomToolDefinition({ toolName: fetch_api_data, description: Fetch data from an API endpoint, inputSchema: z.object({ url: z.url(), method: z.enum([GET, POST]).default(GET), headers: z.record(z.string(), z.string()).optional(), }), exampleInputs: [{ url: https://api.example.com/data, method: GET }], execute: async ({ url, method, headers }) { const response await fetch(url, { method, headers }) const data await response.text() return [ { type: json as const, value: { message: API Response: ${data.slice(0, 5000)}..., }, }, ] }, }) const { output } await client.run({ // 运行自定义 Agentid 必须与下方 agentDefinitions 中的 id 匹配 agent: my-custom-agent, prompt: Today Im feeling very happy!, // 提供自定义 Agent 与自定义工具定义 agentDefinitions: [myCustomAgent], customToolDefinitions: [myCustomTool], handleEvent: (event) { console.log(Codebuff Event, JSON.stringify(event)) }, }) if (output.type error) { console.error(The run failed:\n${output.message}) } else { console.log(The run succeeded with output:, output) } } main()2. 从源码理解getCustomToolDefinition自定义工具的本质是一个CustomToolDefinition对象。查看 sdk/src/custom-tool.ts 的类型定义export type CustomToolDefinitionN extends string string, Args extends any any, Input extends any any { toolName: N inputSchema: z.ZodTypeArgs, Input description: string endsAgentStep: boolean exampleInputs: Input[] execute: (params: Args) PromiseToolResultOutput[] }各字段的语义字段说明toolName工具名Agent 通过它引用该工具inputSchemaZod v4 schema用于校验 LLM 生成的工具入参并转换为 JSON Schema 描述给模型description传给 LLM 的工具说明应描述工具做什么、何时使用endsAgentStep是否为停止序列。为true时LLM 调用该工具后本步骤结束、必须等待工具结果适合给模型提供信息的工具默认trueexampleInputs示例入参数组帮助模型学会正确调用execute工具被调用时的执行函数支持同步或异步必须返回ToolResultOutput[]数组值得注意的底层细节在初始化会话时SDK 会把 Zod schema 通过z.toJSONSchema(inputSchema, { io: input })转换为标准 JSON Schema见 sdk/src/run-state.ts这样自定义工具的输入描述才能在会话状态中被 JSON 序列化、跨运行传递。另外如果你给工具起名时不小心与内置工具ToolName重名类型系统会给出编译期错误提示应改用overrideTools而非customToolDefinitions见 sdk/src/custom-tool.ts。3. 端到端验证Weather Agent 测试仓库提供了完整的自定义 Agent 端到端测试可参考 sdk/e2e/custom-agents/weather-agent.e2e.test.ts。该测试定义了一个weather-agent模型为anthropic/claude-sonnet-4.5toolNames: [get_weather]和对应的get_weather工具然后断言client.run()的返回结果不是 error事件流中存在tool_call事件且toolName get_weather最终回复文本中包含天气相关信息。这验证了自定义工具被 Agent 真实调用、结果被整合进回复的完整链路。仓库中还有api-integration-agent、database-query-agent、apply-patch-tool等更多端到端样例见 sdk/e2e/custom-agents 目录可作为编写自定义 Agent 的参考范式。五、知识文件Knowledge Files为 Agent 注入项目上下文1. 自动发现规则知识文件为 Agent 提供项目上下文。SDK 会自动发现两类文件项目文件每个目录下的knowledge.md、AGENTS.md或CLAUDE.md按此优先级顺序选取用户文件主目录下的~/.knowledge.md、~/.AGENTS.md或~/.CLAUDE.md大小写不敏感匹配。优先级逻辑在源码中有明确实现selectHighestPriorityKnowledgeFile按KNOWLEDGE_FILE_NAMES_LOWERCASE的优先级顺序取第一个匹配项见 sdk/src/run-state.ts而selectKnowledgeFilePaths会对每个目录分别执行一次该选择sdk/src/run-state.ts。用户级文件加载则通过loadUserKnowledgeFiles完成——它会大小写不敏感地扫描主目录下的隐藏文件同样按AGENTS.md CLAUDE.md的优先级取最高者sdk/src/run-state.ts。2. 手动覆盖与合并可以通过knowledgeFiles参数覆盖项目文件发现完全替换或通过userKnowledgeFiles与主目录文件合并await client.run({ agent: codebuff/base0.0.16, prompt: Help me refactor, knowledgeFiles: { knowledge.md: # Guidelines\n- Use TypeScript }, userKnowledgeFiles: { ~/.knowledge.md: # Preferences\n- Be concise }, })参数格式与projectFiles相同键为文件路径值为文件内容文件会直接注入 Agent 上下文。在源码中当未显式提供knowledgeFiles时SDK 会从projectFiles或自动发现的项目文件树中按目录自动挑选知识文件见 sdk/src/run-state.ts。六、文件过滤File Filtering安全边界与 .env 保护1. 内置 .env 安全策略SDK 始终以大小写不敏感方式阻止 Agent 读取.env与.env.*文件唯一的例外是.env.example、.env.sample、.env.template这类模板文件。从源码 sdk/src/tools/read-files.ts 可以看到敏感 env 文件直接返回IGNORED状态根本不会进入读取流程env 模板会被标记为TEMPLATE前缀后返回即模型看到的是示例模板而非真实密钥。2. 自定义fileFilter除内置策略外可通过fileFilter添加项目级规则。fileFilter接收文件路径返回三种状态状态含义blocked阻止读取Agent 看到[BLOCKED]占位allow-example允许读取但内容前加[TEMPLATE]前缀allow正常读取示例——阻止所有.pem私钥文件const client new CodebuffClient({ apiKey: process.env.CODEBUFF_API_KEY, fileFilter: (filePath) { if (filePath.endsWith(.pem)) return { status: blocked } return { status: allow } }, })3. 与 gitignore 的关系重要默认行为内置.env策略始终生效未提供fileFilter时SDK 还会自动应用 gitignore 检查包括对允许的 env 模板提供了fileFilter时额外的过滤决策由调用方负责但 env 模板仍需遵守 gitignore。从源码看判断逻辑位于getFileshasCustomFilter为false即未提供自定义过滤时项目内文件默认执行isFileIgnored当自定义过滤存在时仅对 env 模板继续执行 gitignore 检查sdk/src/tools/read-files.ts。这条内置策略只作用于SDK 中介的 Agent 文件读取包括read_files工具不会给终端命令或内部编辑工具增加限制。同样如果你通过overrideTools.read_files自定义了文件读取实现必须自行保留 env 模板的 gitignore 行为——官方 CLI、Desktop、Web 与 Cloud 桥接实现都已做到这一点。七、加载本地 AgentloadLocalAgents(options)如果你把 Agent 定义以文件形式维护在磁盘上可以用loadLocalAgents批量加载并直接用于client.run()。1. 基本用法import { loadLocalAgents, CodebuffClient } from codebuff/sdk // 从默认位置加载cwd、父目录或主目录中的 .agents const agents await loadLocalAgents({ verbose: true }) // 或者从指定目录加载 // const agents await loadLocalAgents({ agentsPath: ./my-agents }) // 或者加载并校验无效 Agent 会被过滤掉 // const agents await loadLocalAgents({ validate: true, verbose: true }) // 打印每个 Agent 的来源文件路径便于调试 for (const agent of Object.values(agents)) { console.log(${agent.id} loaded from ${agent._sourceFilePath}) } // 将加载的 Agent 用于 client.run() const client new CodebuffClient({ apiKey: process.env.CODEBUFF_API_KEY }) const result await client.run({ agent: my-custom-agent, agentDefinitions: Object.values(agents), prompt: Hello, })2. 参数说明参数类型说明agentsPathstring可选指定 agents 目录路径省略时按{cwd}/.agents、{cwd}/../.agents、{homedir}/.agents的顺序搜索verboseboolean可选是否输出加载过程中的错误日志默认falsevalidateboolean可选加载后是否校验 Agent无效 Agent 会被过滤默认false3. 返回值未开启校验时返回PromiseLoadedAgents即Recordstring, LoadedAgentDefinition按 Agent ID 作为键开启校验时返回LoadLocalAgentsResult包含agents与validationErrors两个字段见 sdk/src/agents/load-agents.ts。每个LoadedAgentDefinition在AgentDefinition基础上增加了_sourceFilePath该 Agent 定义来源的文件路径。另外带handleSteps函数的 Agent 还会保留一份实时函数副本handleStepsFn避免打包器辅助函数在字符串化后无法执行的问题sdk/src/agents/load-agents.ts。4. 支持的文件类型.ts、.tsxTypeScript 文件运行时自动转译.js、.mjs、.cjsJavaScript 文件。以.d.ts结尾或匹配test/spec命名的文件会被排除源码见 sdk/src/agents/load-agents.ts。加载时还会自动跳过node_modules、scripts、skills等目录sdk/src/agents/load-agents.ts。此外loadLocalAgents使用带时间戳的模块 URL 进行动态导入?update${Date.now()}确保 Agent 文件变更后能重新加载sdk/src/agents/load-agents.ts。八、client.run(options)完整参数与返回值1. 参数总表参数类型说明agentstring必填要运行的 Agent。使用base表示默认 Agent或传入自定义 Agent ID配合agentDefinitionspromptstring必填用户提示词描述希望 Agent 完成的任务paramsobject可选额外的 Agent 参数。多数 Agent 不使用部分自定义 Agent 除提示词外还可接收一个 JSON 对象作为输入handleEventfunction可选执行期间每个事件助手消息、工具调用等都会触发的回调可实时流式展示 Agent 进度previousRunobject可选上一次run()返回的 JSON 状态用于延续会话、保持上下文projectFilesobject可选项目的全部文件键为相对当前目录的完整路径值为文件内容如{ src/index.ts: console.log(hi) }帮助 Codebuff 挑选优质上下文文件曾用名allFilesknowledgeFilesobject可选注入每次run()的知识文件schema 与projectFiles相同直接进入 Agent 上下文agentDefinitionsarray可选自定义 Agent 定义数组需满足AgentDefinition类型customToolDefinitionsarray可选自定义工具定义数组每个工具含名称、Zod 校验 schema 与处理函数供 Agent 在执行中调用maxAgentStepsnumber可选Agent 停止前允许执行的最大步数作为防止失控的安全阀合理值约为 20更多可选参数在源码类型中有详细注释sdk/src/run.ts例如content多模态消息内容数组支持文本图片、signalAbortSignal 取消运行、skillsDir技能目录、env注入终端命令的环境变量、onStateSnapshot运行中周期性状态检查点回调可在进程被杀后恢复进行中的回合等。其中onStateSnapshot默认每 5 秒触发一次见 sdk/src/run.ts且快照计时器调用了unref()不会阻止宿主进程退出sdk/src/run.ts。2. 返回值RunStaterun()返回一个 Promise解析为成功或失败对象成功包含RunState对象可传入下一次运行的previousRun参数以继续对话失败包含一个Error对象具备name、message、stack属性。RunState对象包含sessionState传给下一次运行的内部状态outputAgent 的输出文本、错误或其他类型traceSessionId本次会话的追踪 ID类型定义见 sdk/src/run-state.ts。实际使用中通过result.output.type error判断运行是否失败然后读取output.message这在前面的自定义 Agent 示例中已有体现。九、进阶从源码看 SDK 内部机制1. 一次run()的调用链CodebuffClient.run()实际委托给模块级run()函数sdk/src/run.ts后者主要做三件事校验推断来源区分 Codebuff 托管推理与 BYOK自带模型推理并检查恢复的会话是否绑定到了不同的推理连接——绑定不一致会直接返回错误而不是静默切换凭据sdk/src/run.ts检查取消信号若AbortSignal已中止返回带中断说明的错误输出执行runOnce初始化会话状态首次运行或基于previousRun.sessionState应用覆盖项、解析用户身份、将用户消息发送给 Agent 运行时callMainPrompt期间通过handleEvent/handleStreamChunk推送事件与流式文本块。从底层调用看run()会分别处理response-chunk主 Agent 回复、subagent-response-chunk子 Agent 回复和reasoning_delta推理过程增量三类流式数据sdk/src/run.ts这为构建类似 CLI 的流式交互界面提供了依据。2. 项目索引与 token 评分当传入projectFiles时SDK 内部会用 tree-sittercodebuff/code-map对每个文件做符号解析并计算 token 分数从而帮助 Agent 挑选最相关的上下文文件。该计算有 CPU 与 wasm 内存开销因此 SDK 提供了computeProjectIndexFromFiles让宿主提前计算一次、随后通过projectIndex参数复用见 sdk/src/run-state.ts 与类型注释。若解析失败SDK 会降级为空分数并继续运行sdk/src/run-state.ts。3. 会话取消与错误恢复SDK 对中断场景做了细致处理取消或出错时通过buildCancelledSessionState生成可恢复的状态——它会丢弃工具调用已发出但结果未返回的半步骤、必要时把用户提示词补回历史并附加中断说明sdk/src/run.ts。这样即使运行被终止后续用previousRun恢复时也能从结构合法的历史继续。网络层错误空闲超时、瞬时网络错误、API 错误码、国家/地区封锁等也会被归一化为带statusCode、errorCode等字段的结构化错误输出sdk/src/run.ts。4. MCP、技能与校验SDK 的扩展面除 README 重点介绍的能力外SDK 还从 sdk/src/index.ts 导出MCP 支持loadMCPConfig/loadMCPConfigSync从.agents/mcp.json加载 MCP 服务器配置支持$VAR_NAME环境变量引用解析且后面的目录覆盖前面的目录项目配置优先于全局见 sdk/src/agents/load-mcp-config.ts技能SkillsloadSkills/loadSkillsSync从SKILL.md目录加载技能供 Agent 的skill工具使用Agent 校验validateAgents可在加载后对 Agent 定义做完整性校验错误与重试工具isRetryableStatusCode、createHttpError、重试退避常量等便于宿主实现健壮的错误处理。5. 连接检查与 BYOKCodebuffClient还提供了checkConnection()方法通过请求后端/api/healthz接口5 秒超时判断连通性BYOK 场景下则改为直接探测自建推理服务见 sdk/src/client.ts。若你想完全脱离 Codebuff 账号、使用自己的模型密钥本地推理可通过byok选项配置ResolvedByokConnection——此时 SDK 不会向 Codebuff 发送身份、用量等数据且会从子进程环境中剔除凭据相关的环境变量防止 Agent 通过终端工具读到密钥sdk/src/run.ts。十、总结codebuff/sdk提供了一条从官方默认 Agent到完全自定义 Agent 自定义工具的平滑能力曲线两行起步new CodebuffClient()client.run()即可驱动 Codebuff 编码代理多轮会话previousRun让复杂任务可以分步推进、保持上下文业务集成getCustomToolDefinitionAgentDefinition让 LLM 能安全地调用你自己的 API 与业务逻辑工程化.agents目录的loadLocalAgents、.agents/mcp.json的 MCP 加载、validate校验与文件过滤策略使其可以嵌入到 CI、桌面应用或云端服务等真实产品形态中。该 SDK 采用 MIT 协议开源所有类型定义与实现均可在仓库sdk/目录下继续深入研究相关端到端用例集中在 sdk/e2e/custom-agents 与 sdk/src/tests如 client.test.ts、run-file-filter.test.ts、user-knowledge-files.test.ts可作为二次开发的验证基线。【免费下载链接】freebuffThe free coding agent项目地址: https://gitcode.com/GitHub_Trending/cod/freebuff创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/15 14:22:40

UE5预测IK详解:原理、参数配置与三类实战应用

1. 项目概述1.1 这个功能到底是干嘛的聊预测IK之前,先说说我自己的状态。搞了三年UE5,普通的两骨骼IK、FABRIK甚至控制骨骼这些老一套我自认为玩得挺转,结果第一次碰到"预测IK"这个节点时直接懵了。官方文档翻了几遍,只…

2026/9/15 14:32:41

sqlmap深度实战:从SQL注入检测到企业级安全巡检

1. 这不是黑客工具,而是一把数据库安全的听诊器sqlmap——这三个字母在渗透测试工程师的日常里,几乎等同于“SQL注入检测”的代名词。它不是用来搞破坏的黑产脚本,而是一个高度工程化的、开源的自动化SQL注入与数据库接管工具。我第一次在客户…

2026/9/15 4:54:30

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/15 0:01:16

AI英语单词APP开发:自适应学习算法与移动端优化实践

1. 项目概述 作为一名在移动应用开发领域摸爬滚打多年的老手,我最近完成了一个AI英语单词APP的开发项目。这个项目将传统单词记忆方法与现代AI技术相结合,打造了一款能够智能适应不同用户学习习惯的英语学习工具。 市面上大多数单词APP都存在一个通病&a…

2026/9/15 0:01:16

Flutter与OpenHarmony结合开发手语学习APP实战

1. 项目背景与核心价值作为一名同时接触过Flutter和OpenHarmony的开发者,最近我完成了一个基于Flutter for OpenHarmony的手语学习APP实战项目。这个项目最大的特点在于实现了跨平台框架与国产操作系统深度结合的创新实践——用Flutter开发的应用能完美运行在OpenHa…

2026/9/15 0:01:16

六个月成为机器人工程师:从ROS2到SLAM的实战路径

1. 六个月的紧迫感从哪来:先搞清楚你要成为哪种机器人工程师说实话,六个月的期限并不是一个宽松的时间线。市面上任何一本正经的机器人学教材都超过五百页,ROS2的官方文档可以翻到你怀疑人生,再加上ABB、KUKA这些工业机器人厂家动…

2026/9/15 14:22:53

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/14 13:53:59

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/15 11:42:23

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码