多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

【Bug已解决】Stale docstring parameters in langchain-core (_write, set_text)

【Bug已解决】Stale docstring parameters in langchain-core (_write, set_text) 【Bug已解决】Stale docstring parameters in langchain-core (_write, set_text)一、现象长什么样langchain-core里_write和set_text两个函数的docstring 参数描述过期stale了文档里写的参数名、参数顺序、默认值和函数现在的真实签名对不上。典型表现docstring 列了参数path但函数签名早已改成file_path/destination。docstring 说有参数mode默认w但实现把它删了或改名append。参数顺序在文档里是(content, path)实际是(path, content)照文档调用直接错位。某个参数被标为required实际有默认值或反过来。阅读源码的人尤其想接这些内部 API 的贡献者照 docstring 写调用轻则TypeError: unexpected keyword argument重则参数错位导致写错文件/内容。这类文档与签名漂移在内部函数上更常见因为内部函数改动频繁、docstring 容易被忘。二、背景_write和set_text是 langchain-core 里处理把文本/内容写入某处的辅助函数比如写缓存文件、写中间产物。它们的签名随重构调整过几次参数重命名、增删、换位但 docstring 是手写的没有强制和签名同步于是慢慢腐化。由于这些是带下划线前缀的内部函数很多人以为内部函数不用管文档但 langchain-core 被大量下游依赖内部 API 也会被间接用到docstring 过期照样误导。三、根因根因三点docstring 无签名校验没有任何工具比对 docstring 的Args:与函数signature的参数名漂移无感知。重构只改签名不改文档重命名/增删参数时习惯改代码忘改注释。缺 doctest/类型检查兜底如果 docstring 示例能被执行或参数能被静态类型检查过期会更快暴露。本质参数的事实来源是函数签名但文档是另一份独立文本两者无绑定必然随迭代不一致。四、最小可运行复现下面演示漂移导致的错误调用def _write(content, path, modew): # 当前真实签名 with open(path, mode) as f: f.write(content) # docstring 还写着_write(path, content, appendFalse) # 用户照 docstring 调 _write(/tmp/x.txt, hello) # 实际把 /tmp/x.txt 当 content把 hello 当 path # 结果试图 open(hello)写进错误位置或报权限错误修复让 docstring 与签名一致并在改签名时同步文档。def _write(content: str, path: str, mode: str w) - None: Write content to a file. Args: content: text to write. path: destination file path. mode: file open mode, default w. with open(path, mode) as f: f.write(content)五、解决方案第一层最小直接修复最小修法把_write/set_text的 docstringArgs:改成与当前签名逐字一致参数名、顺序、默认值并补一个可运行的 doctest 示例。def set_text(self, path: str, text: str, *, overwrite: bool True) - None: Set text content at path. Args: path: target path. text: content to set. overwrite: if True replace existing, else append. Example: obj.set_text(/tmp/a, hi) ...这一层让照文档调用不再错位。六、解决方案第二层结构化改进把docstring 参数必须与签名一致固化成策略对象作为单一事实来源并用inspect在测试里自动比对。import inspect from dataclasses import dataclass, field from typing import List dataclass(frozenTrue) class LangChainStaleDocstringPolicy: docstring 参数一致性策略的单一事实来源。 must_match_signature: bool True run_doctest: bool True tracked_funcs: List[str] field(default_factorylambda: [_write, set_text]) def check(self, func) - None: if not self.must_match_signature: return sig inspect.signature(func) params [p for p in sig.parameters if p ! self] doc inspect.getdoc(func) or for p in params: if f{p}: not in doc and f {p} not in doc: raise AssertionError(fdocstring missing param {p} for {func.__name__}) def validate(self) - None: if self.run_doctest and not self.must_match_signature: raise AssertionError(doctest needs signature match)CI 用policy.check扫描tracked_funcsdocstring 缺参数即报错。七、解决方案第三层断言 / CI 守护用 pytest 锁死参数一致性import pytest import inspect from policy import LangChainStaleDocstringPolicy as P def test_doc_has_all_params(): p P() def _write(content, path, modew): _write. Args: content: x. path: y. mode: z. pass p.check(_write) # 不抛即通过 def test_doc_missing_param_fails(): p P() def _write(content, path): _write. Args: content: x. pass with pytest.raises(AssertionError): p.check(_write) def test_doctest_required(): with pytest.raises(AssertionError): P(run_doctestTrue, must_match_signatureFalse).validate()CI 加一条对langchain_core的tracked_funcs跑policy.checkdocstring 参数漂移即阻断。八、排查清单照 docstring 调_write参数错位→ docstring 参数名/顺序过期。文档说有mode实际没有→ 签名改了文档没改。是否有签名-文档比对→ 用inspectpolicy.check。内部函数是否也要管文档→ 下游间接依赖必须管。是否补了 doctest→ 可执行示例能兜底漂移。set_text是否同样问题→ 两个函数都要修并纳入追踪。九、小结langchain-core的_write与set_textdocstring 参数描述和真实签名漂移参数名/顺序/默认值对不上照文档调用会错位甚至写错文件。根因是 docstring 是独立于签名的文本、无校验、重构时忘改。第一层把 docstring 改成与签名逐字一致并补 doctest第二层用LangChainStaleDocstringPolicy把一致性策略固化成单一事实来源并用inspect自动比对第三层用 pytest CI 守护。API 文档的通用原则参数事实来源是签名docstring 必须机器校验与签名一致内部函数也不例外。
返回列表