Skill 06 · Agent Observability Experiment Bootstrap
Subchapter 6.9
references/python/providers/langchain.mdMarkdown2 KBView on GitHub
Triggered by introspection (Workflow step 2.5) when the call-site function imports from langchain / langchain_openai / langchain_anthropic / etc. and uses one of:
langchain.*.invoke(...)ChatOpenAI(...), ChatAnthropic(...), ChatVertexAI(...), ChatBedrock(...), etc.LLMChain(...)LangChain is a meta-framework — it wraps a specific provider. Walk one level deeper: the chat-client class names the provider. Read the user’s function (and immediate imports) to identify which Chat* class is instantiated, then emit the assert for THAT provider per the table below:
| LangChain class | Underlying provider | Reference file |
|---|---|---|
ChatOpenAI, OpenAI, AzureChatOpenAI (with azure_endpoint=) | OpenAI / Azure OpenAI | providers/openai.md or providers/openai.md (Azure: also AZURE_OPENAI_ENDPOINT) |
ChatAnthropic, AnthropicLLM | Anthropic | providers/anthropic.md |
ChatVertexAI, ChatGoogleGenerativeAI | Vertex / Gemini | providers/gemini.md |
ChatBedrock, BedrockLLM | AWS Bedrock | providers/bedrock.md |
ChatLiteLLM | LiteLLM (auto-routes) | providers/litellm.md |
Emit the assert for the underlying provider, not LangChain itself. Example: if the user’s function has from langchain_anthropic import ChatAnthropic, emit:
assert os.getenv("ANTHROPIC_API_KEY"), "ANTHROPIC_API_KEY is required for the wired task_fn (LangChain ChatAnthropic)."If the call-site uses multiple chat clients (rare), emit asserts for each.
chain.invoke({...}) returns either a string (for simple chains) or an AIMessage (for chat-based chains). Extract .content if it’s the latter.prompt | llm | parser) return the parser’s output type directly — usually a string. Trust the user’s function signature.chain.ainvoke(...) — wrap with asyncio.run(...).ChatOpenAI(api_key="sk-...")). If the user’s function passes a key explicitly, the env var is irrelevant — emit a # Note: comment instead of an assert.prompts/ directory conventions vary widely; the wrapped function should encapsulate prompt loading, so task_fn just calls function(input_data) and trusts the chain.