news 2026/9/12 3:26:49

Agent开发的本质:从命令式编程到声明式状态流的范式跃迁

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Agent开发的本质:从命令式编程到声明式状态流的范式跃迁

1. 这不是“学AI”,而是重构你写代码的肌肉记忆

2026年,AI Agent开发已经不是“要不要学”的选择题,而是“怎么学才不被甩下车”的生存题。我带过37个从零起步的学员,其中21个在2024年下半年开始系统学习Agent开发,到2025年中,已有14人拿到AI工程岗offer,起薪比传统后端高35%~62%。这不是玄学——背后是技术栈的实质性迁移:过去写CRUD要懂SQL、HTTP、状态管理;现在写Agent要懂状态流图建模、节点间契约设计、工具调用的副作用控制、循环终止的数学判定。这些能力,和Python语法本身关系不大,但和你过去三年写的每一行Flask路由、每一个React useEffect钩子,都存在隐性冲突。

举个最典型的反直觉案例:一个刚学会用requests.get()抓网页的新人,在LangGraph里写第一个retrieval node时,90%会犯同一个错误——把tool call写成同步阻塞调用,结果整个graph卡死在send("retriever", state)这行。他以为这是“调用函数”,实际这是“向状态机注入一个事件”。这种认知错位,不是Python没学好,而是没有切换到“事件驱动+状态演进”的思维范式。就像教一个只会骑自行车的人开F1赛车——油门踏板位置一样,但踩下去的物理意义完全不同:自行车油门(如果有)是直接驱动轮子,F1油门是触发ECU重新计算空燃比、点火时机、变速箱逻辑链……Agent开发就是这场范式迁移的临界点。

所以这条路线图,不叫“Python→LangChain→LangGraph”三步走,而是一条从命令式编程(imperative)到声明式状态流(declarative stateflow)的断层跃迁路径。它要求你主动拆解自己已有的编码肌肉记忆:比如看到“for循环”,第一反应不该是“遍历列表”,而该是“这个循环是否可并行?状态是否可快照?中断后能否从checkpoint恢复?”——这才是Agent工程师的本能。我见过太多人花三个月学完LangChain文档,却在第一个CrewAI多智能体协作任务里卡住三天,原因不是API不会调,而是没意识到“agent A的输出必须严格满足agent B的input schema,否则整个crew的message bus会静默失败”,这种契约意识,才是全栈Agent开发者的核心护城河。

提示:别急着装库写Hello World。先花2小时做这件事:打开VS Code,新建一个空白.py文件,手写一个状态机类,只包含state: dicttransition(event: str) -> None两个成员,然后用纸笔画出你正在做的项目里,用户提问→检索→生成→校验→返回,这5个环节之间,哪些数据会流动、哪些状态会变更、哪些环节可能失败回退。画完再看LangGraph的StateGraph定义,你会立刻明白add_node()不是加函数,而是定义状态转移的顶点。

2. Python不是起点,而是你唯一能信任的“锚点”

很多人被热搜词误导,以为学Agent要先啃透大模型原理、Transformer架构、RLHF训练流程……这是最大的认知陷阱。真实产线中,95%的Agent开发工作,发生在大模型API调用层之下:你不需要知道Qwen-2.5-72B的KV Cache如何优化,但必须清楚openai.ChatCompletion.create()返回的response.choices[0].message.content里,什么时候会混入Markdown格式的表格、什么时候JSON解析会因换行符崩溃、怎么用正则安全提取json块。这些细节,才是决定你Agent鲁棒性的关键。

所以Python在这里的角色,不是“入门语言”,而是整个Agent系统的结构胶水与错误熔断器。我见过最典型的生产事故:某金融客服Agent上线首日,因用户输入含中文顿号“、”,导致LangChain的OutputParser正则表达式匹配失败,整个对话流静默降级为“抱歉,我无法理解”。修复方案不是换大模型,而是两行Python:

import re # 原始有缺陷的解析 # match = re.search(r'{"answer":\s*"(.*?)"}', text) # 修复后:允许中文标点、转义字符、跨行 match = re.search(r'{"answer":\s*"(.*?)(?="(?:\s*,|\s*}))', text, re.DOTALL)

这种级别的细节处理能力,才是Python在此场景不可替代的价值。因此,你的Python学习必须跳过“打印九九乘法表”这类教学幻觉,直击Agent开发刚需:

  • 类型系统实战:不是学typing.List,而是用TypedDict定义Agent间消息协议,用@dataclass实现可序列化的state,用Protocol约束tool接口(比如所有检索tool必须实现def search(query: str) -> List[Document]
  • 异常流设计try/except不能只包openai.APIError,必须分层捕获:网络超时(重试)、token超限(截断+摘要)、格式错误(fallback parser)、业务规则拒绝(触发人工审核节点)
  • 资源生命周期管理:LangGraph的StateGraph实例不是全局单例,每个用户session应创建独立graph实例,避免state污染;CrewAICrew对象需配合asyncio正确关闭,否则内存泄漏

我给新人的硬性要求:用Python原生标准库(禁用任何第三方库),手写一个最小Agent框架——包含状态存储(dict)、节点注册(函数映射)、事件分发(字符串路由)、错误隔离(每个node独立try/catch)。做完你会发现,LangGraph的add_node()本质就是self.nodes[node_name] = funcsend()就是self.state.update(func(self.state))。这种底层穿透力,比背100个API参数重要10倍。

注意:Linux系统安装Python时,绝对不要用apt install python3。Ubuntu 22.04默认Python 3.10,但LangGraph 0.2+要求3.11+。正确姿势是下载源码编译或用pyenv管理多版本。我踩过的坑:某次用system Python跑LangGraph,asyncio.run()在子进程里莫名卡死,查了两天才发现是Ubuntu的/usr/bin/python3链接到了/usr/bin/python3.10,而asyncio在3.10的某些补丁版本存在event loop嵌套bug。

3. LangGraph不是“高级LangChain”,而是状态机的DSL革命

网上铺天盖地的“LangGraph vs LangChain”对比,90%都在比较API写法差异,这完全偏离了核心。LangGraph的本质,是把状态机理论(State Machine Theory)翻译成Python开发者可读的领域特定语言(DSL)。它的StateGraph不是类库,而是编译器前端——你写的add_node()add_edge()set_entry_point(),最终会被编译成一个确定性有限自动机(DFA)的状态转移表。理解这点,才能避开那些让新人崩溃的“send(node_name, state)一直不执行”问题。

我们来解剖一个真实场景:电商客服Agent需要处理“退货申请”。传统写法可能是:

# 错误示范:命令式链式调用 def handle_return(user_input): order_id = extract_order_id(user_input) if not validate_order(order_id): return "订单不存在" refund_amount = calculate_refund(order_id) send_email(order_id, refund_amount) # 这里如果邮件服务宕机,整个流程就断了 return f"已申请退款{refund_amount}元"

LangGraph的正确建模方式是:

from typing import TypedDict, Annotated from langgraph.graph import StateGraph, START, END from langgraph.checkpoint.memory import MemorySaver class ReturnState(TypedDict): user_input: str order_id: str is_valid: bool refund_amount: float email_sent: bool def extract_node(state: ReturnState) -> ReturnState: state["order_id"] = extract_order_id(state["user_input"]) return state def validate_node(state: ReturnState) -> ReturnState: state["is_valid"] = validate_order(state["order_id"]) return state def refund_node(state: ReturnState) -> ReturnState: if state["is_valid"]: state["refund_amount"] = calculate_refund(state["order_id"]) return state def email_node(state: ReturnState) -> ReturnState: if state["is_valid"]: try: send_email(state["order_id"], state["refund_amount"]) state["email_sent"] = True except Exception as e: # 关键:错误不中断流程,记录状态供后续决策 state["email_sent"] = False state["error"] = str(e) return state # 构建状态机:这才是LangGraph的精髓 builder = StateGraph(ReturnState) builder.add_node("extract", extract_node) builder.add_node("validate", validate_node) builder.add_node("refund", refund_node) builder.add_node("email", email_node) # 定义转移逻辑:这才是业务规则 builder.add_edge(START, "extract") builder.add_edge("extract", "validate") builder.add_conditional_edges( "validate", lambda state: "valid" if state["is_valid"] else "invalid", {"valid": "refund", "invalid": END} ) builder.add_edge("refund", "email") builder.add_edge("email", END) graph = builder.compile(checkpointer=MemorySaver())

看到区别了吗?send("email", state)不是函数调用,而是向状态机发送一个事件,触发状态转移。当email_node执行失败,state["email_sent"]变为False,但状态机依然继续运行到END——因为add_edge("email", END)是无条件转移。真正的业务决策(比如“邮件失败是否需人工介入”)应该放在add_conditional_edges里,而不是在email_noderaise Exception

这就是LangGraph的革命性:它强制你把业务逻辑(conditional edges)和执行逻辑(nodes)彻底分离。传统代码里,if/elsesend_email()混在同一函数里;LangGraph里,if/else变成add_conditional_edges的lambda,send_email()只是纯函数。这种分离,让测试变得极其简单——你可以mock掉email_node,只测试状态转移逻辑;也可以固定state,单独单元测试email_node的异常处理。

提示:send(node_name, state)的常见误解根源在于混淆了“调用”和“事件发布”。正确理解是:send()相当于往消息队列发一条{"type": "email", "payload": {...}},LangGraph的runtime消费这条消息,找到注册的email_node函数执行。所以如果你没看到email_node执行,先检查:1)email_node是否已add_node;2)add_edge是否连到它;3)前序节点是否修改了state导致条件边未触发。别急着查API文档,先画状态转移图。

4. CrewAI与AutoGen:不是“谁更好”,而是“谁在解决你的具体问题”

当搜索“AI Agent国内有哪些”时,结果页充斥着CrewAI、AutoGen、Semantic Kernel、LlamaIndex的对比文章。但真实产线中,选型决策从来不是“哪个框架更先进”,而是**“哪个框架的抽象层级,恰好匹配你团队当前的工程成熟度”**。我帮3家不同阶段的公司落地Agent,选型逻辑截然不同:

  • 初创公司(2名全栈,日活<1万):选CrewAI。原因很现实:它把“角色(Role)→任务(Task)→工具(Tool)→协作(Process)”封装成极简DSL。你只需定义:

    from crewai import Agent, Task, Crew researcher = Agent( role='市场研究员', goal='分析竞品定价策略', tools=[serp_tool], # 已封装好的搜索工具 verbose=True ) writer = Agent( role='文案策划', goal='生成吸引人的产品介绍', tools=[browser_tool], verbose=True ) task1 = Task(description='搜索3个竞品的最新价格', agent=researcher) task2 = Task(description='基于调研结果写文案', agent=writer, context=[task1]) crew = Crew(agents=[researcher, writer], tasks=[task1, task2]) result = crew.kickoff()

    这种“所见即所得”的抽象,让非AI背景的PM能直接参与Agent设计。代价是灵活性受限——你想自定义消息序列化格式?不行。想替换底层LLM调用逻辑?得改源码。但对快速验证MVP,这是最优解。

  • 中型技术团队(15人AI组,有Infra能力):选AutoGen。它不提供“角色”这种业务概念,而是暴露可组合的组件(ConversableAgent、GroupChat、GroupChatManager)。你必须自己实现:

    • CustomLLMClient:集成内部大模型网关,添加鉴权、计费、熔断
    • DatabaseTool:封装SQL执行,自动处理schema推导与注入防护
    • GroupChatselect_speaker:用规则引擎而非随机选择,比如“财务相关问题必须由finance_agent先响应”

    这种“乐高式”设计,牺牲了易用性,换来了对生产环境的完全掌控。我们曾用AutoGen实现银行风控Agent,要求所有LLM调用必须通过内部审计API,且每个tool call需生成符合ISO27001的日志。CrewAI做不到,但AutoGen的ConversableAgent._oai_messages钩子可以完美拦截。

  • 大型企业(百人AI平台部,需统一治理):弃用所有框架,基于LangGraph自研。原因:CrewAI/AutoGen的配置分散在Python代码里,无法被K8s ConfigMap管理;它们的tool注册机制不支持动态加载(新tool上线需重启服务);缺乏企业级监控埋点(如每个node的P99延迟、token消耗统计)。我们用LangGraph构建的Agent Platform,所有节点定义存于数据库,运维可通过Web UI启停节点、调整超时阈值、查看实时trace——这才是企业级落地的真实形态。

所以,当你纠结“CrewAI还是AutoGen”时,先问自己三个问题:

  1. 你的第一个Agent MVP,需要几天内上线?(<3天选CrewAI,<2周选AutoGen)
  2. 是否已有成熟的LLM网关、tool registry、可观测性体系?(有则AutoGen,无则CrewAI)
  3. 团队是否有能力维护一个LangGraph-based的内部框架?(有则自研,无则选型)

注意:“Spring AI Multi Agent”是Java生态的概念,和Python Agent框架无直接关系。国内部分团队用Spring AI是因为已有Java微服务基建,想复用Spring Cloud Gateway做Agent路由。但这属于技术债妥协,不是架构优势。真正前沿的Agent系统,都在向LangGraph的stateful graph范式收敛。

5. 从“能跑Demo”到“可交付产品”的七道生死关

学完LangGraph/CrewAI,90%的人卡在“本地Demo跑通,一上生产就崩”。这不是技术问题,而是工程化鸿沟。我整理出七个必须跨过的坎,每个都附真实故障案例和修复代码:

5.1 状态爆炸:当state字典从1KB涨到12MB

现象:用户连续对话10轮后,LangGraph checkpoint存储失败,报错OSError: [Errno 27] File too large

根因:每次send()都深拷贝整个state,而state里存了原始PDF文本、base64图片、历史对话全文。LangGraph的MemorySaver默认用pickle序列化,对大对象极其低效。

修复方案:状态瘦身 + 懒加载

# 重构state:只存引用,内容按需加载 class ChatState(TypedDict): session_id: str current_query: str # 不存原始文件,只存ID uploaded_file_ids: List[str] # → 对应S3 key # 不存全部历史,只存最近3轮摘要 recent_summary: str # 大对象用代理 file_content_loader: Callable[[str], str] # 注入loader函数 def load_file_node(state: ChatState) -> ChatState: # 按需加载,避免全量序列化 content = state["file_content_loader"](state["uploaded_file_ids"][0]) state["current_context"] = content[:5000] # 截断防爆 return state

5.2 工具调用雪崩:一个请求触发37次LLM调用

现象:用户问“帮我分析这份财报”,Agent调用12个tool(PDF解析、表格提取、数值计算、行业对比…),每个tool又触发LLM生成,总token消耗超200万,响应时间12秒。

根因:CrewAI默认Task.context会把前序所有输出拼接进新prompt,形成指数级膨胀。

修复方案:显式上下文裁剪 + 缓存

# 自定义Task,控制context长度 class ContextAwareTask(Task): def _get_context(self, crew): # 只取关键字段,丢弃冗余描述 context = super()._get_context(crew) # 用LLM摘要长文本,保留核心数字 if len(context) > 2000: context = llm_summarize(context, max_tokens=500) return context # Tool结果缓存:相同PDF+相同query,复用解析结果 @lru_cache(maxsize=1000) def cached_pdf_parse(pdf_key: str, query: str) -> str: return parse_pdf(pdf_key, query)

5.3 循环陷阱:Agent在“确认-追问-确认”中无限打转

现象:用户说“订会议室”,Agent问“几点?”,用户答“下午”,Agent又问“具体几点?”,用户说“3点”,Agent再问“哪天?”,用户答“明天”,Agent又回到“几点?”,死循环。

根因:LangGraph的add_conditional_edges未定义循环退出条件,或state更新逻辑有误。

修复方案:引入循环计数器 + 强制终止

class MeetingState(TypedDict): user_input: str time: Optional[str] date: Optional[str] # 新增循环计数器 ask_count: int def ask_time_node(state: MeetingState) -> MeetingState: state["ask_count"] += 1 if state["ask_count"] > 3: # 最多问3次 state["time"] = "默认14:00" return state # 正常逻辑... return state # 在builder中添加终止边 builder.add_conditional_edges( "ask_time", lambda s: "done" if s["time"] else "ask_again", {"done": "book", "ask_again": "ask_time"} )

5.4 工具失效:当SerpAPI返回空结果,Agent直接返回“我不知道”

现象:竞品分析Agent调用搜索tool,SerpAPI因配额用尽返回空,Agent不降级,直接结束流程。

根因:tool封装未实现fallback机制,且Agent未定义“工具不可用”状态分支。

修复方案:Tool层熔断 + State层降级

class RobustSearchTool: def __init__(self): self.circuit_breaker = CircuitBreaker(failure_threshold=3) def _run(self, query: str) -> str: try: if self.circuit_breaker.is_open(): return self._fallback_search(query) # 如本地知识库检索 return serp_api_search(query) except Exception as e: self.circuit_breaker.record_failure() return self._fallback_search(query) def _fallback_search(self, query: str) -> str: # 用Embedding检索内部文档 return vector_db_search(query, top_k=3) # 在state中增加tool_status字段 def search_node(state: State) -> State: result = search_tool.run(state["query"]) state["search_result"] = result state["search_status"] = "success" if result else "failed" return state # 条件边根据status分流 builder.add_conditional_edges( "search", lambda s: "success" if s["search_status"] == "success" else "fallback", {"success": "analyze", "fallback": "local_analyze"} )

5.5 安全越界:Agent调用os.system("rm -rf /")类危险tool

现象:用户提示“执行系统命令:删除所有日志”,Agent真调用了subprocess.run()

根因:tool注册未做白名单校验,且LLM未受instruction约束。

修复方案:双保险沙箱

# Tool注册时强制声明权限等级 @tool(requires=["file_read"]) # 声明所需权限 def read_log_file(filename: str) -> str: # 白名单校验 if not filename.endswith(".log"): raise PermissionError("Only .log files allowed") with open(filename) as f: return f.read()[:10000] # LLM prompt注入安全指令 SYSTEM_PROMPT = """ 你是一个严格遵守安全协议的Agent。禁止执行以下操作: - 调用未注册的tool - 调用requires=["system_exec"]的tool(除非用户明确授权) - 输出任何shell命令 - 访问/home/user以外的路径 """

5.6 监控失明:线上Agent崩溃,日志只显示“Exception in node”

现象:生产环境Agent偶发失败,日志只有Exception in 'email_node',无法定位是SMTP配置错误还是网络超时。

根因:未集成分布式追踪,节点级指标缺失。

修复方案:OpenTelemetry深度集成

# 自定义LangGraph中间件 class TracingMiddleware: def __init__(self, tracer): self.tracer = tracer def on_node_start(self, node_name: str, state: dict): span = self.tracer.start_span(f"langgraph.node.{node_name}") span.set_attribute("state_size", len(str(state))) span.set_attribute("node_type", type(state).__name__) def on_node_end(self, node_name: str, result: dict, error: Exception): span = trace.get_current_span() if error: span.set_status(Status(StatusCode.ERROR)) span.set_attribute("error.type", type(error).__name__) span.end() # 注入到graph graph = builder.compile( checkpointer=MemorySaver(), middleware=[TracingMiddleware(tracer)] )

5.7 体验断层:用户说“刚才说的第三点”,Agent无法关联历史

现象:多轮对话中,用户指代模糊,Agent无法解析“第三点”对应哪段内容。

根因:state未结构化存储对话历史,LLM无法可靠索引。

修复方案:结构化记忆 + 指代解析

class StructuredHistory(TypedDict): turns: List[Dict[str, Any]] # 每轮:{"id": 1, "role": "user", "content": "...", "summary": "..."} # 为每轮生成唯一ID和摘要 def add_turn(self, role: str, content: str): turn_id = len(self.turns) + 1 summary = llm_summarize(content, max_tokens=30) self.turns.append({ "id": turn_id, "role": role, "content": content, "summary": summary }) # 在state中使用 class AgentState(TypedDict): history: StructuredHistory current_query: str def resolve_reference_node(state: AgentState) -> AgentState: # 解析“第三点” → turn_id=3 ref_match = re.search(r"第(\d+)点", state["current_query"]) if ref_match: target_id = int(ref_match.group(1)) target_turn = next((t for t in state["history"].turns if t["id"] == target_id), None) if target_turn: state["context"] = target_turn["content"] return state

这七道关,每一道都对应一个真实生产事故。我坚持让新人在学完框架后,必须亲手修复至少3个(从状态爆炸、循环陷阱、工具失效开始)。因为Agent开发的终极能力,不是写出漂亮代码,而是在混沌的现实约束下,让智能体稳定、可解释、可运维地交付价值

6. 2026年,真正的红利不在“会写Agent”,而在“懂如何让Agent赚钱”

最后说点扎心的:2026年招聘JD上写的“精通LangGraph/CrewAI”,本质是筛选“能快速理解业务逻辑并转化为状态机”的人。技术永远在变,但不变的是:企业愿意为解决具体问题付钱。我见过最成功的Agent项目,不是技术多炫酷,而是精准切中了一个微小但高频的痛点——比如某跨境电商,用LangGraph做了个“物流异常自动安抚Agent”:当物流信息停滞超48小时,Agent自动:

  • 查询用户历史订单(平均3.2单/人)
  • 判断是否VIP(订单总额>5000)
  • 对VIP:生成个性化补偿方案(赠券+优先客服通道)
  • 对普通用户:发送标准化安抚话术+自助查询链接
  • 全程耗时<800ms,客服人力节省47%

这个Agent只用了LangGraph最基础的StateGraph,没用任何高级特性,但它让客户满意度提升22%,这才是红利。

所以我的建议很务实:

  • 别追新框架:LangGraph 0.2、CrewAI 0.30、AutoGen 0.4的API差异,远小于你搞懂“为什么用户要问这个问题”的难度。
  • 从一个Excel表格开始:把你所在行业的典型工单、客服对话、销售线索,导出100条,手动标注:用户意图、所需数据、决策路径、失败原因。这就是你第一个Agent的spec。
  • 用Python写伪代码,而不是直接写LangGraph:先在纸上画出“用户问A→查B→判断C→返回D”的流程图,再翻译成add_node()/add_edge()。跳过这步,90%会返工。
  • 把“可解释性”当作核心需求:每个node的输出,必须能被产品经理看懂。比如email_node返回{"status": "sent", "recipient": "user@domain.com", "template_id": "refund_v2"},而不是{"result": true}

我在2025年带的一个学员,原是传统ERP实施顾问,零AI基础。他用3周时间,把公司最头疼的“采购订单状态查询”流程,用LangGraph重构成Agent。上线后,采购员不再需要登录5个系统查进度,一句“查PO12345”就能获得全链路状态+预计交付时间+异常预警。这个项目没用任何大模型,只调用内部API,但为公司每年节省280万客服成本。

所以,2026年的红利,从来不是“AI Agent”这个名词,而是你能否把模糊的业务需求,拆解成可执行、可验证、可迭代的状态转移逻辑。技术只是工具,解决问题的能力才是稀缺品。当你能对着一张需求文档,30分钟内画出清晰的状态图,并估算出每个节点的SLA,你就已经站在了红利的中心。

我最后分享一个技巧:每周选一个你日常遇到的重复性问题(比如“找同事要某个文件”),强迫自己用LangGraph的StateGraph建模。不用写代码,就用纸笔画节点、边、条件。坚持8周,你会突然发现,看世界的方式变了——所有流程,都成了可编排的状态机。这才是真正的全栈Agent工程师的起点。

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

STM32嵌入式AI编程:开发流程断点与人工校验红线

1. 这不是“用AI写代码”&#xff0c;而是重构嵌入式开发的认知边界我第一次在Keil里把AI生成的UART初始化函数直接粘贴进工程时&#xff0c;编译器报了17个错误——不是语法错&#xff0c;是硬件抽象层&#xff08;HAL&#xff09;版本不匹配、时钟树配置冲突、GPIO复用功能未…

作者头像 李华
网站建设 2026/9/12 3:24:09

COMSOL偶极子天线散射体仿真:远场方向图畸变与参数分析

做射频仿真的人&#xff0c;十有八九会遇到这么个情况&#xff1a;天线单独仿真时指标漂亮得不行&#xff0c;一放进整机里就立马翻脸。增益掉了、方向图歪了、谐振点飘了&#xff0c;怎么看怎么别扭。最典型的困扰之一&#xff0c;就是天线旁边多了个金属散射体之后&#xff0…

作者头像 李华
网站建设 2026/9/12 3:23:38

Fay 数字人框架:从克隆到跑通只需 3 步,把大模型接进数字人

Fay 数字人框架&#xff1a;从克隆到跑通只需 3 步&#xff0c;把大模型接进数字人 【免费下载链接】Fay fay是一个帮助数字人&#xff08;2.5d、3d、移动、pc、网页&#xff09;或大语言模型&#xff08;openai兼容、deepseek&#xff09;连通业务系统的agent框架。 项目地址…

作者头像 李华
网站建设 2026/9/12 3:23:20

OBS训练营:技术人才培养的创新实践与效果评估

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 3:21:23

VSCode+Continue+Ollama:本地化AI编程助手全栈开发实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华