我们始终欢迎代码贡献!无论是修复错误、添加功能还是改进性能,您的贡献都有助于为数千名开发者提供更好的开发体验。
在提交大型新功能或重构之前,请先在论坛中讨论您的想法。这有助于确保与项目目标一致,并避免重复工作。此要求不适用于错误修复或小型改进,您可以直接通过拉取请求贡献这些内容。请务必在PR描述中链接任何相关的问题。使用以便在PR合并时自动关闭问题。新的集成应遵循集成指南。
核心理念
所有代码贡献都应遵循以下核心原则:
测试优先
每个变更必须包含全面的测试,以验证正确性并防止回归
快速开始
快速修复:提交错误修复
对于简单的错误修复,您可以立即开始:
克隆和设置
git clone https://github.com/您的用户名/复刻的代码库名称.git
# 例如,对于LangChain:
git clone https://github.com/parrot123/langchainjs.git
# 对于LangGraph:
git clone https://github.com/parrot123/langgraphjs.git
# 在您的代码库内,安装依赖
pnpm install
# 为所有包创建构建以解析工作区依赖关系
pnpm build
创建分支
git checkout -b 您的用户名/简短的错误修复名称
添加测试
包含单元测试,这些测试在没有您的修复时会失败。这使我们能够验证错误已解决并防止回归 运行构建
运行构建命令以确保包仍能正确构建pnpm build
# 或构建特定的工作区包
pnpm --filter @langchain/core build
运行测试
在提交PR之前,确保所有测试在本地通过pnpm lint
pnpm test
# 对于涉及集成的错误修复,还需运行:
pnpm test:int
# 或在特定的工作区包中运行测试
cd libs/langchain-core
pnpm test
pnpm lint
# 或从代码库根目录运行特定包的测试
pnpm --filter @langchain/core test
pnpm --filter @langchain/core lint
提交拉取请求
遵循提供的PR模板。如果适用,使用关闭关键词(例如 Fixes #123)引用您正在修复的问题。
完整开发设置
对于持续开发或较大的贡献:
贡献指南
查看我们的贡献指南,了解功能、错误修复和集成的相关要求
开发环境
我们的JS/TS项目使用pnpm进行依赖管理。请确保您安装了最新版本,或运行 corepack enable(在Node 24+上)以设置所需的pnpm版本。
为您正在处理的包设置开发环境。
对于 langchain-core 的更改:pnpm install
# 从包目录运行包的测试
cd libs/langchain-core
pnpm test
# 或从代码库根目录运行包的测试
pnpm --filter @langchain/core test
对于 langchain 的更改:pnpm install
pnpm --filter langchain test # 在开始开发前确保测试通过
对于合作伙伴集成的更改:pnpm install
pnpm --filter @langchain/{provider} test # 在开始开发前确保测试通过
对于社区集成的更改:pnpm install
pnpm --filter @langchain/community test # 在开始开发前确保测试通过
正在进行中 - 即将推出!在此期间,请遵循LangChain的说明。
代码库结构
LangChain组织为包含多个包的monorepo:
位于 libs/providers/,这些是用于特定集成的独立版本包。例如:
正在进行中 - 即将推出!在此期间,请遵循LangChain的说明。
开发工作流
测试要求
每个代码变更必须包含全面的测试。
单元测试
位置:src/tests/被测试的文件名.test.ts要求:
- 不允许网络调用
- 测试所有代码路径,包括边缘情况
- 为外部依赖使用模拟
# 运行整个测试套件
pnpm test
# 或运行特定的测试文件
pnpm test src/tests/被测试的文件名.test.ts
# 或运行特定的测试函数
pnpm test -t "应运行的测试"
集成测试
集成测试需要访问外部服务/提供商API(这可能会产生费用),因此默认不运行。并非每个代码变更都需要集成测试,但请注意,我们将在审查过程中单独要求/运行集成测试。位置:src/tests/被测试的文件名.int.test.ts要求:
- 测试与外部服务的真实集成
- 使用环境变量存储API密钥
- 如果凭据不可用,则优雅跳过
测试质量检查清单
- 当您的代码被破坏时测试失败
- 测试边缘情况和错误条件
- 正确使用fixture和模拟
代码质量标准
质量要求:
必需:所有函数的完整类型function processDocuments(
docs: Document[],
processor: DocumentProcessor,
batchSize: number = 100
): ProcessingResult {
// ...
}
必需:所有导出函数和接口的JSDocs/**
* 文档处理实例。
*/
interface FooDocumentProcessor {
/**
* 批量处理文档。
*
* @param docs - 要处理的文档列表。
* @returns 包含成功/失败计数的处理结果。
*/
process(docs: Document[]): ProcessingResult;
}
/**
* 批量处理文档。
*
* @param docs - 要处理的文档列表。
* @param processor - 文档处理实例。
* @param batchSize - 每批文档数量。
* @returns 包含成功/失败计数的处理结果。
*/
export function processDocuments(
docs: Document[],
processor: DocumentProcessor,
batchSize: number = 100
): ProcessingResult {
// ...
}
- 记录所有参数和返回值
- 为复杂函数包含使用示例
- 记录引发的异常
- 关注”为什么”而非”是什么”
自动化:格式化和代码检查:pnpm lint # 检查风格和类型
pnpm format # 应用格式化
标准:
- 描述性变量名
- 拆分复杂函数(目标少于20行)
- 遵循代码库中的现有模式
贡献指南
向后兼容性
不允许对公共API进行破坏性变更,除非是关键安全修复。有关主要版本发布的详细信息,请参阅我们的版本策略。
保持兼容性:
始终保留:
- 函数签名和参数名称
- 类接口和方法名称
- 返回值结构和类型
- 公共API的导入路径
可接受的修改:
-
添加新的可选参数/类型参数
-
向类添加新方法
-
在不改变行为的情况下提高性能
-
添加新模块或函数
-
这会破坏现有的用户代码吗?
-
检查您的目标是否为公共API
-
测试中是否存在现有的使用模式?
错误修复
对于错误修复贡献:
重现问题
创建一个展示错误的最小测试用例。维护者和其他贡献者应该能够运行此测试并看到失败,而无需额外的设置或修改
记录变更
如果行为发生变化,更新文档字符串;为复杂逻辑添加注释
新功能
我们对新功能的准入门槛较高。通常,如果没有现有问题证明外部贡献者提出的新核心抽象、基础设施变更、依赖项变更或新代理/链有迫切需求,我们不会接受这些贡献。
通常,功能贡献要求包括:
设计讨论
打开一个问题描述:
- 您正在解决的问题
- 提议的API设计
- 预期的使用模式
实施
- 遵循现有的代码模式
- 包含全面的测试和文档
- 考虑安全影响
集成考虑
- 这与现有功能如何交互?
- 是否有性能影响?
- 这会引入新的依赖项吗?
我们将拒绝可能导致安全漏洞或报告的功能。
安全指南
安全检查清单:
-
验证和清理所有用户输入
-
在模板和查询中正确转义数据
-
绝不使用
eval(),因为这可能导致任意代码执行漏洞
- 使用特定的异常类型
- 不要在错误消息中暴露敏感信息
- 实现适当的资源清理
- 避免添加硬依赖
- 保持可选依赖最少
- 审查第三方包的安全问题
测试和验证
在本地运行测试
在提交PR之前,请确保您已完成以下步骤。请注意,LangChain和LangGraph的要求略有不同。
PR提交
推送您的分支并打开拉取请求。遵循提供的表单模板。使用关闭关键词注明相关问题。提交后,请等待并检查以确保CI检查通过。如果有任何检查失败,请及时解决问题 - 维护者可能会在合理时间内关闭未通过CI的PR。 正在进行中 - 即将推出!在此期间,请遵循LangChain的说明。
测试编写指南
为了编写有效的测试,有几个良好实践需要遵循:
- 将测试封装在描述被测试组件的
describe 块中
- 使用自然语言描述测试名称
- 断言要详尽
- 仅对合理大小的数据对象使用快照
describe("DocumentProcessor", () => {
it("应处理空文档列表", () => {
const processor = new DocumentProcessor();
const result = processor.process([]);
expect(result.success).toBe(true);
expect(result.processedCount).toBe(0);
expect(result.errors).toHaveLength(0);
});
});
describe("ChatOpenAI", () => {
it("应使用真实API进行测试", () => {
const chat = new ChatOpenAI();
const response = chat.invoke("Hello");
});
});
describe("APIService", () => {
it("应使用重试调用", () => {
const mockClient = new MockClient();
const service = new APIService(client: mockClient);
const result = service.callWithRetry();
});
});
获取帮助
我们的目标是拥有尽可能易于访问的开发人员设置。如果您在设置过程中遇到任何困难,请在社区Slack中询问或打开论坛帖子。
您现在已准备好为LangChain贡献高质量的代码了!