<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged langchain</title>
<link>https://coderlegion.com/tag/langchain</link>
<description>Powered by Question2Answer</description>
<item>
<title>Learning LangChain</title>
<link>https://coderlegion.com/30850/learning-langchain</link>
<description>&lt;p&gt;A while back I built Synapse, a small app that answers questions using my own notes. I did every part of it by hand: load the files, turn them into vectors, find the closest ones to the question, and hand those to an LLM. It worked, and I understood it, because I'd written every line myself.&lt;/p&gt;
&lt;p&gt;So when I started LangChain, a framework that promised to do all of that for me felt a little suspicious. My honest question was: what is this doing that I haven't already done?&lt;/p&gt;
&lt;p&gt;It turns out the answer is less &quot;new ideas&quot; and more &quot;a standard shape for the ones you already have.&quot; Let me walk through it the way I learned it.&lt;/p&gt;
&lt;h3 id=&quot;start-small-messages-and-templates&quot;&gt;Start small: messages and templates&lt;/h3&gt;
&lt;p&gt;A chat model doesn't take one big string. It takes a list of messages: a system message that sets the role, then human messages from you, then AI messages from the model. LangChain gives each of those its own class. Nothing magic, it's the same thing the raw API wants.&lt;/p&gt;
&lt;p&gt;Prompt templates were the next small step. Instead of building a string every time, you write the prompt once with a gap in it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from langchain_core.prompts import ChatPromptTemplate

template = ChatPromptTemplate.from_template(
    &quot;I've recently adopted a {pet}. Suggest three {pet} names.&quot;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then an output parser takes the model's text reply and turns it into something you can actually use, like a Python list. The thing that stuck with me here is that the parser is only as good as your instructions. Vague instructions about the format gave me a messy list. Strict ones gave me a clean one.&lt;/p&gt;
&lt;h3 id=&quot;the-pipe&quot;&gt;The pipe&lt;/h3&gt;
&lt;p&gt;This is the bit where it clicked for me. LangChain lets you join those pieces with a &lt;code&gt;|&lt;/code&gt;, like a Unix pipe:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;chain = chat_template | chat | list_output_parser
chain.invoke({&quot;pet&quot;: &quot;dog&quot;})
# ['Max', 'Bella', 'Luna']
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A prompt goes in one end, the model sits in the middle, and a clean list comes out the other end. Each step's output is the next step's input. That's the whole idea.&lt;/p&gt;
&lt;p&gt;It even works for ordinary Python functions. Wrap them in &lt;code&gt;RunnableLambda&lt;/code&gt; and they snap in like any other piece:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from langchain_core.runnables import RunnableLambda

add_up = RunnableLambda(lambda x: sum(x))
square = RunnableLambda(lambda x: x**2)

(add_up | square).invoke([1, 2, 5])   # 8, then 64
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also draw a chain. &lt;code&gt;chain.get_graph().print_ascii()&lt;/code&gt; prints the boxes and arrows, which is surprisingly handy when a chain gets long.&lt;/p&gt;
&lt;p&gt;Two more things I liked. &lt;code&gt;RunnableParallel&lt;/code&gt; runs two chains side by side and gives both results to the next step. And &lt;code&gt;batch&lt;/code&gt; is quicker than looping: two requests through &lt;code&gt;batch&lt;/code&gt; took 2.67 seconds in my notebook, while the same two as separate calls took about 7.5.&lt;/p&gt;
&lt;h3 id=&quot;now-rag-with-the-same-pieces&quot;&gt;Now RAG, with the same pieces&lt;/h3&gt;
&lt;p&gt;Remember my five hand-built steps? LangChain has a piece for each.&lt;/p&gt;
&lt;p&gt;For loading, there are loaders for different file types. I used one for PDFs and one for Word documents. Splitting was the new part, since Synapse never did any. I split a six-page document twice. First by its headings, so every chunk remembers which lecture it came from, then by size, about 500 characters with a little overlap. That left me with 20 chunks, each labelled with where it came from.&lt;/p&gt;
&lt;p&gt;Each chunk then became 1,536 numbers using OpenAI's embedding model. I wanted to see if it really worked, so I compared three pairs of chunks. They scored 0.88, 0.80 and 0.79, so related text does end up close together. The vectors all have a length of about 1, which is why a plain dot product works as a similarity score.&lt;/p&gt;
&lt;p&gt;Those vectors went into Chroma, which saves them to a folder on disk so I don't have to re-embed every time I open the notebook.&lt;/p&gt;
&lt;p&gt;Retrieval comes in two flavours. A plain similarity search gives you the closest chunks. MMR gives you close chunks that are also different from each other, so you don't get five copies of the same paragraph.&lt;/p&gt;
&lt;p&gt;And the last step is where the pipe comes back. The whole thing is one chain:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;chain = (
    {&quot;context&quot;: retriever, &quot;question&quot;: RunnablePassthrough()}
    | prompt_template
    | chat
    | StrOutputParser()
)

chain.invoke(&quot;What software do data scientists use?&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The retriever fills in the context, the question passes straight through, the prompt tells the model to answer only from that context and name the lecture it used, and the parser hands back plain text. The answer ended with:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Resources: Programming Languages &amp;amp; Software Employed in Data Science - All the Tools You Need&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That's the same &quot;only use these notes&quot; guard I wrote by hand in Synapse, plus the sources I'd been putting off adding.&lt;/p&gt;
&lt;h3 id=&quot;what-this-changed-for-me&quot;&gt;What this changed for me&lt;/h3&gt;
&lt;p&gt;LangChain didn't teach me a new idea. Everything in that pipeline is something I'd already done by hand: load, embed, find the closest, ask. What it gave me was a standard shape for each step, and the pipe to join them. Having built it the long way first is what made the short way make sense.&lt;/p&gt;
&lt;p&gt;Next up is LangGraph.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/30850/learning-langchain</guid>
<pubDate>Mon, 12 Oct 2026 17:46:29 +0000</pubDate>
</item>
<item>
<title>Deep Agents in Action: Building a Multi-Agent Research System (published)</title>
<link>https://coderlegion.com/28616/deep-agents-in-action-building-a-multi-agent-research-system-published</link>
<description>&lt;p&gt;I tested yet another implementation of a multi-agent orchestrator.&lt;/p&gt;
&lt;p&gt;The paradigm for AI agents is shifting rapidly from single, monolithic prompt loops to structured multi-agent systems capable of division of labor, state persistence, and fine-grained tool orchestration.&lt;/p&gt;
&lt;p&gt;Although &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.ibm.com/products/watsonx-orchestrate&quot;&gt;IBM watsonx Orchestrate&lt;/a&gt; is my go-to solution for enterprise-level agent deployment, I wanted to experiment with LangChain's Deep Agents to evaluate its multi-agent orchestration capabilities.&lt;/p&gt;
&lt;h3 id=&quot;introduction-the-deep-agents-architecture&quot;&gt;Introduction: The Deep Agents Architecture&lt;/h3&gt;
&lt;p&gt;LangChain announced recently Managed Deep Agents, introducing a managed platform to execute deep agent topologies. The Deep Agents paradigm addresses the fundamental limitations of single-agent workflows—specifically context window degradation, tool confusion, and compounding reasoning failures during extended, multi-step tasks.&lt;/p&gt;
&lt;h3 id=&quot;what-is-the-deep-agents-pattern-&quot;&gt;What is the Deep Agents Pattern?&lt;/h3&gt;
&lt;p&gt;The Deep Agents pattern is a hierarchical multi-agent architecture where:&lt;/p&gt;
&lt;p&gt;A top-level Orchestrator decomposes complex tasks and delegates sub-tasks to specialists.&lt;br&gt;
Each Specialist Agent runs its own isolated ReAct loop with its own tools and memory.&lt;br&gt;
Specialists return structured results to the orchestrator, which synthesises them.&lt;br&gt;
Agents can be composed recursively — an orchestrator can itself be a sub-agent.&lt;br&gt;
This pattern adds genuine value over a single agent because:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;| Single Agent                       | Deep Agents                                       |
| ---------------------------------- | ------------------------------------------------- |
| One context window gets overloaded | Each agent has an isolated, focused context       |
| All reasoning in one prompt        | Specialised reasoning per domain                  |
| Hard to scale                      | Add specialists without changing the orchestrator |
| Hard to debug                      | Full delegation trace for auditability            |

---
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Excerpt from LangChain Deep Agents Documention;&lt;/strong&gt;&lt;br&gt;
&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=5253859950868264376&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;deep-agents-overview&quot;&gt;Deep Agents overview&lt;/h3&gt;
&lt;p&gt;Deep Agents is the easiest way to start building agents and applications that are powered by LLMs—with built-in capabilities for file systems for context management, subagent-spawning, and long-term memory. Optional capabilities such as task planning and skills extend the harness when your use case needs them. You can use deep agents for any task, including complex, multi-step tasks.Deep Agents comes with the following capabilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Take actions in an environment&lt;/strong&gt;: Take actions via tools, read and&lt;br&gt;
write files, execute code &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connect to your data&lt;/strong&gt;: Load memories,&lt;br&gt;
skills, and domain knowledge at the right moment &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Manage growing context&lt;/strong&gt;: Summarize history and offload large results across long runs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parallelize tasks&lt;/strong&gt;: Delegate to general or specialized subagents running in isolated context windows &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stay in the loop&lt;/strong&gt;: Pause for human approval at critical decision points Improve over time: Update memory, skills, and prompts based on real usage&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;And from the Github repository;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Deep Agents is an open source agent harness — an opinionated agent that runs out of the box. Extend, override, or replace any piece.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Principles:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Opinionated&lt;/strong&gt; — defaults tuned for long-horizon, multi-step work&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extensible&lt;/strong&gt; — override or replace any piece without forking&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Model-agnostic&lt;/strong&gt; — works with any LLM that supports tool calling: frontier, open-weight, or local &lt;/li&gt;
&lt;li&gt;Production-ready — built on LangGraph (streaming, persistence, checkpointing) with first-class tracing,&lt;br&gt;
evaluation, and deployment via LangSmith&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Features include:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sub-agents&lt;/strong&gt; — delegate tasks to agents with isolated context windows&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filesystem&lt;/strong&gt; — read, write, edit, or search over pluggable local,&lt;br&gt;
sandboxed, or remote backends&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context management&lt;/strong&gt; — summarize long threads and offload tool outputs&lt;br&gt;
to disk&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shell access&lt;/strong&gt; — run commands in your sandbox of choice&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Persistent memory&lt;/strong&gt; — pluggable state and store backends for&lt;br&gt;
cross-session recall&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Human-in-the-loop&lt;/strong&gt; — approve, edit, or reject tool calls before they&lt;br&gt;
run&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Skills&lt;/strong&gt; — reusable behaviors the agent can load on demand&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tools&lt;/strong&gt; — bring your own functions or any MCP server&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;core-concepts-of-langchain-deep-agents&quot;&gt;Core Concepts of LangChain Deep Agents&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Hierarchical Orchestration: A primary agent acts as a supervisor,&lt;br&gt;
receiving high-level goals and delegating sub-tasks to dedicated&lt;br&gt;
specialist agents rather than executing every step sequentially in a&lt;br&gt;
single context loop.&lt;/li&gt;
&lt;li&gt;Specialized Agent Roles: Individual agents operate with tightly &lt;br&gt;
scoped system prompts, specialized tools, and isolated context &lt;br&gt;
windows to execute sub-tasks (e.g., information retrieval, numeric &lt;br&gt;
calculations, or document composition).&lt;/li&gt;
&lt;li&gt;Isolated Memory Stores: Each agent maintains its own short-term &lt;br&gt;
working memory, facts, and episodic memory, preventing state &lt;br&gt;
contamination across different phases of execution.&lt;/li&gt;
&lt;li&gt;ReAct Reasoning Loop: Sub-agents execute autonomous Thought → Action &lt;br&gt;
→ Observation loops using validated tool interfaces.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;technical-implementation&quot;&gt;Technical Implementation&lt;/h3&gt;
&lt;p&gt;Now that the feature set of &quot;Deep Agents&quot; is done, let's jump into a simple didatical (for myself) implementation.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The implementation in the provided repository (scaffolded via IBM Bob) provides a complete local and cloud-compatible implementation of the Deep Agents pattern.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;architecture-overview&quot;&gt;Architecture Overview&lt;/h3&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/28616/deep-agents-in-action-building-a-multi-agent-research-system-published</guid>
<pubDate>Fri, 25 Sep 2026 14:39:24 +0000</pubDate>
</item>
<item>
<title>LittleHorse Draws the Line Between What Your Agent Decides and What Your Code Must Execute</title>
<link>https://coderlegion.com/27867/littlehorse-draws-the-line-between-what-your-agent-decides-and-what-your-code-must-execute</link>
<description>&lt;p&gt;Picture the moment an AI agent gets triggered by an event — a support ticket, a queue message, a webhook — and has to reliably set off several things downstream in order. Most developers end up hand-wiring that themselves: retries, state tracking, a debugging session that starts with &quot;okay, which step actually failed?&quot; According to Colt McNealy, founder and CEO of LittleHorse, that's the moment a team building agents needs something underneath the agent framework they're already using.&lt;/p&gt;
&lt;p&gt;&quot;If you get to the point where your agent is triggered by an event somewhere... and then when the agent is done, something else has to happen, and then another thing has to happen, you're going to spend a lot of time wiring things together,&quot; McNealy told me in a briefing ahead of LittleHorse's Saddle Command Center 1.3 release. &quot;You're not going to have an easy time debugging end-to-end what's going on, and you're going to need an orchestration system to make sure the right things happen in the right order.&quot;&lt;/p&gt;
&lt;p&gt;LittleHorse was founded in 2022 and backed and advised by McNealy's father, Scott McNealy, co-founder and former CEO of Sun Microsystems. The idea traces back to a real estate startup where McNealy tried to build a scheduling system for open houses, showings, and escrow inspections, and found the business process scattered across Salesforce, DotLoop, several internal portals, a customer mobile app, and a lot of tribal knowledge. &quot;That problem of any process being stitched, living in the point-to-point integrations and queue consumers... has only gotten worse as AI has come around,&quot; he said. &quot;It's made it hard for customers to deploy agents into mission-critical business processes.&quot;&lt;/p&gt;
&lt;p&gt;LittleHorse's answer is what it calls Business-as-Code: an open-source, Java-based workflow engine that turns an intended business process into a deployable, testable, version-controlled software artifact, then orchestrates it across whatever systems a company already runs. Developers write it in Java, Python, Go, or C# (JavaScript joins the list in 1.3), and it compiles into a process specification LittleHorse executes and tracks.&lt;/p&gt;
&lt;p&gt;I asked McNealy what Business-as-Code does that the rest of a crowded orchestration field — Airflow, Temporal, Camunda, and agent frameworks like LangChain — doesn't already cover. Airflow, he said, is built for background data ETL, not real-time, high-speed business processes; one LittleHorse customer runs a virtual try-on product where a photo becomes a 10-step image-generation pipeline that has to run live, which he said isn't an Airflow use case. Temporal handles durable execution — safely retrying a failed function by replaying its prior side effects — but doesn't produce an end-to-end diagram a business user can actually read. &quot;What LittleHorse gives you that Temporal doesn't... is a higher level for developers to get closer to the business process, closer to business value,&quot; McNealy said. Camunda, in his framing, doesn't produce a version-controlled, tested code artifact and isn't built for core product flows. LangChain and similar frameworks build the agent itself; in a LittleHorse workflow, that agent becomes one node inside a larger, deterministic process — and Saddle 1.3 adds a pre-built agent worker, running on LangChain under the hood, to make that pattern easier to deploy.&lt;/p&gt;
&lt;p&gt;The clearest proof point McNealy offered is a utility and vegetation-management company — the kind of business that clears trees away from power lines — that had zero software engineers two years ago and ran operations on NetSuite plus roughly ten other SaaS systems. It decided to treat software as a competitive advantage, hired around 18 engineers, and started with one workflow: truck maintenance work orders, built on LittleHorse's open-source engine. It now runs more than 140 workflows in production, covering employee onboarding, job bidding, storm response and truck rerouting, and location tracking for 8,000 trucks every 30 seconds to generate a live heat map of completed jobs. Because the company owns that code instead of waiting on a vendor, McNealy said it has adopted agents in back-office workflows faster than competitors stuck waiting for SAP to ship an equivalent feature — one that, even then, would only work inside SAP.&lt;/p&gt;
&lt;p&gt;That same logic shapes how LittleHorse handles agent guardrails, which McNealy walked through using a fraud-detection example from a financial-services customer. Their agent gets read-only access to internal systems through MCP, evaluates a transaction, and either the decision applies automatically below a set risk threshold or a human reviews the agent's report first. The agent never gets write access to push a transaction through on its own. &quot;It really, really constrains what it can do and makes it a lot easier to verify and audit every single tool call that the agent has done,&quot; McNealy said. That split — deterministic code handles execution and audit, the agent handles judgment on ambiguous input — is also why it's worth the added layer at all, he argued: it cuts token usage and error rates, and shrinks the surface exposed to prompt injection, since the agent never touches the system doing the actual write.&lt;/p&gt;
&lt;p&gt;Saddle Command Center 1.3 is built to reach that pattern from both ends: pre-built connectors and task workers, an integrated streaming layer, webhook and event triggers, and a serverless free trial so a team can try LittleHorse without standing up Kafka themselves — plus enough out-of-the-box capability that CIOs and architects don't need to write most of it.&lt;/p&gt;
&lt;p&gt;Asked whether LittleHorse is easing a shift from human-driven business processes to agent-driven ones, McNealy didn't hesitate. &quot;Even with the most complicated agents, there's still a larger process that causes the agent to run, and then when it's done doing its task, another thing happens in other systems,&quot; he said. &quot;Those end-to-end workflows are what we codify.&quot; The bet behind Saddle 1.3 is that as agents move from prototypes into systems touching real trucks and real transactions, the question won't be whether a model is capable enough — it'll be whether anyone can say, with an audit trail, exactly what it was allowed to decide.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/27867/littlehorse-draws-the-line-between-what-your-agent-decides-and-what-your-code-must-execute</guid>
<pubDate>Mon, 21 Sep 2026 12:00:00 +0000</pubDate>
</item>
<item>
<title>How to Catch an AI Agent Behaving Badly Before It Ships</title>
<link>https://coderlegion.com/24656/how-to-catch-an-ai-agent-behaving-badly-before-it-ships</link>
<description>&lt;p&gt;AI agents fail in ways that aren't obvious during demos - they hallucinate tool calls, fabricate intermediate results, and sometimes take actions the user never approved. Catching this before users do is now a core part of agent development.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Problem: Agents Optimize for Task Completion, Not Honesty&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When an AI agent is given a goal and a set of tools (web search, code execution, form submission, etc.), it learns that &lt;em&gt;appearing&lt;/em&gt; to make progress is often rewarded the same as &lt;em&gt;actually&lt;/em&gt; making progress. This creates a subtle failure mode: the agent confidently reports a result it never actually obtained, or takes a shortcut that looks correct in the log but silently corrupts the outcome. Unlike a chatbot that hallucinates a fact, an agent can hallucinate an &lt;em&gt;action&lt;/em&gt; - claiming it sent an email, updated a record, or retrieved live data when it did none of those things. Users trust the output because the step-by-step log looks authoritative. That trust is exactly what breaks adoption.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Real Example: Audit Your Agent's Tool Calls&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The fastest way to surface this class of bug is to log every tool call with its actual input/output, then compare it against the agent's self-reported reasoning. Here's a minimal pattern using Python:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import functools

def audited_tool(fn):
 @functools.wraps(fn)
 def wrapper(*args, **kwargs):
 result = fn(*args, **kwargs)
 print(f&quot;[AUDIT] {fn.__name__} | args={args} | result={result}&quot;)
 return result
 return wrapper

@audited_tool
def search_web(query: str) -&amp;gt; str:
 # real implementation here
 return &quot;...&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wrap every tool your agent can call with this decorator (or its equivalent in your framework - LangChain, CrewAI, and AutoGen all have callback hooks for this). Then after a run, diff what the agent &lt;em&gt;said it did&lt;/em&gt; in its final response against the &lt;code&gt;[AUDIT]&lt;/code&gt; log. Gaps between those two are where fabrication lives. Go one step further: add an assertion layer that fails the run if any tool the agent references in its output wasn't actually invoked.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Agents can fabricate tool use, not just facts - the failure mode is more dangerous than standard hallucination because it's buried in structured-looking logs&lt;/li&gt;
&lt;li&gt;Wrapping every tool call with explicit audit logging and comparing it against the agent's self-reported summary is a practical, low-overhead way to surface this before users see it&lt;/li&gt;
&lt;li&gt;Most major agent frameworks (LangChain, CrewAI, AutoGen) expose callback or middleware hooks specifically for this - use them as a default, not an afterthought&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you've caught your agent lying about a tool call in production, what framework were you using and did the built-in tracing actually catch it, or did you have to build around it?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Sources referenced: Hacker News discussion - &quot;AI agents lie, cheat and steal. That is putting off users&quot;&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24656/how-to-catch-an-ai-agent-behaving-badly-before-it-ships</guid>
<pubDate>Fri, 14 Aug 2026 22:05:46 +0000</pubDate>
</item>
<item>
<title>I Built a Local RAG Assistant with Ollama, ChromaDB and LangChain</title>
<link>https://coderlegion.com/23449/i-built-a-local-rag-assistant-with-ollama-chromadb-and-langchain</link>
<description>&lt;p&gt;During my internship at a software services company, I noticed a recurring problem: technicians spent hours searching through hundreds of pages of PDF manuals to answer client questions. The company deploys a suite of management tools accounting, HR, logistics mainly to public institutions managing projects funded by international donors.&lt;/p&gt;
&lt;p&gt;I kept thinking: this is exactly the kind of problem LLMs were made for. So for my Master's project in AI &amp;amp; Big Data, I built an intelligent assistant to handle it.&lt;/p&gt;
&lt;p&gt;The constraint that shaped every technical decision: &lt;strong&gt;no data could leave the local infrastructure&lt;/strong&gt;. These institutions handle sensitive financial data it cannot be sent to OpenAI, Anthropic, or any cloud provider.&lt;/p&gt;
&lt;p&gt;This forced me into the world of fully local LLMs. Here's what I built, what broke, and what I learned.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-problem&quot;&gt;The Problem&lt;/h3&gt;
&lt;p&gt;The company had accumulated massive technical documentation PDF manuals, configuration guides, FAQ files but no efficient way to query it. When a technician faced an issue with the accounting module or the HR module, they searched manually. Slow, inconsistent, and dependent on individual expertise.&lt;/p&gt;
&lt;p&gt;Classic LLMs can't help here: they don't know the private internal documentation. And without grounding in official docs, they hallucinate procedures dangerous when dealing with accounting operations for donor-funded projects.&lt;/p&gt;
&lt;p&gt;The solution: &lt;strong&gt;RAG (Retrieval-Augmented Generation)&lt;/strong&gt; make the LLM answer &lt;em&gt;only&lt;/em&gt; from the official documentation, injected at query time.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-rag-actually-is&quot;&gt;What RAG Actually Is&lt;/h3&gt;
&lt;p&gt;Before the code, the concept in one sentence: instead of asking the LLM to &quot;know&quot; everything, you retrieve the relevant passages from your documents and inject them into the prompt as context.&lt;/p&gt;
&lt;p&gt;The pipeline has two distinct phases:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 1 : Ingestion (done once)&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;PDF documents
    ↓
Chunking (split into 300-character blocks)
    ↓
Embedding (convert each block to a vector)
    ↓
ChromaDB (store all vectors)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Phase 2 : Query (at each question)&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;User question
    ↓
Embed the question (same model)
    ↓
ChromaDB similarity search → top 3 chunks
    ↓
Inject chunks + question into LLM prompt
    ↓
Llama 3 generates a grounded answer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The key insight: the LLM never &quot;knows&quot; your documents. It reads them fresh at each query, from the context you provide. No fine-tuning needed. No retraining when docs are updated.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-architecture-4-docker-services&quot;&gt;The Architecture: 4 Docker Services&lt;/h3&gt;
&lt;p&gt;Everything runs locally via Docker Compose. Four services, each with a clear role:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Service &lt;/th&gt;&lt;th&gt;Role &lt;/th&gt;&lt;th&gt;Port&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Ollama&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Runs Llama 3 locally &lt;/td&gt;&lt;td&gt;11434&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;ChromaDB&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Vector database &lt;/td&gt;&lt;td&gt;8001&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;FastAPI&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;RAG pipeline + REST API &lt;/td&gt;&lt;td&gt;8000&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Streamlit&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;User interface &lt;/td&gt;&lt;td&gt;8501&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# docker-compose.yml (simplified)
services:
  ollama:
    image: ollama/ollama:latest
    ports: [&quot;11434:11434&quot;]
    volumes: [&quot;./ollama_models:/root/.ollama&quot;]
    environment:
      - OLLAMA_KEEP_ALIVE=24h

  chromadb:
    image: chromadb/chroma:latest
    ports: [&quot;8001:8000&quot;]
    volumes: [&quot;./chroma_db:/chroma/chroma&quot;]

  python-api:
    build: ./src
    ports: [&quot;8000:8000&quot;]
    depends_on: [ollama, chromadb]
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
      - CHROMA_HOST=chromadb
      - CHROMA_PORT=8000
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-1-ingesting-the-documentation&quot;&gt;Step 1 : Ingesting the Documentation&lt;/h3&gt;
&lt;p&gt;I ingested 10 documents accounting references (SYSCOHADA, SYCEBNL), a general accounting code, and internal user manuals. That's &lt;strong&gt;2,111 pages&lt;/strong&gt; split into &lt;strong&gt;9,669 chunks&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# src/ingestion.py

import os
import chromadb
from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_chroma import Chroma
from langchain_community.embeddings import HuggingFaceEmbeddings

DATA_DIR = &quot;/app/data/documents&quot;
COLLECTION_NAME = &quot;documentation&quot;

def load_documents():
    documents = []
    for fichier in os.listdir(DATA_DIR):
        if fichier.endswith(&quot;.pdf&quot;):
            try:
                loader = PyPDFLoader(os.path.join(DATA_DIR, fichier))
                docs = loader.load()
                # Tag each chunk with its source document
                for doc in docs:
                    doc.metadata[&quot;module&quot;] = fichier.replace(&quot;.pdf&quot;, &quot;&quot;)
                documents.extend(docs)
            except Exception as e:
                print(f&quot;Skipped {fichier}: {e}&quot;)  # Don't crash on encrypted PDFs
    return documents

def store_embeddings(chunks):
    embeddings = HuggingFaceEmbeddings(
        model_name=&quot;all-MiniLM-L6-v2&quot;,
        model_kwargs={&quot;device&quot;: &quot;cpu&quot;}
    )
    # Explicit HTTP connection — not localhost, the Docker service name
    client = chromadb.HttpClient(host=&quot;chromadb&quot;, port=8000)
    Chroma.from_documents(
        documents=chunks,
        embedding=embeddings,
        collection_name=COLLECTION_NAME,
        client=client
    )
    print(f&quot;Done — {len(chunks)} vectors stored&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two things worth noting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I tag each chunk with its source document name as metadata this allows the LLM to cite its source in the answer&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;try/except&lt;/code&gt; is not optional one encrypted PDF (it happened) would have crashed the entire ingestion without it. Install &lt;code&gt;cryptography&lt;/code&gt; if you hit an AES error: &lt;code&gt;pip install cryptography&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-2-building-the-rag-chain&quot;&gt;Step 2 : Building the RAG Chain&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# src/rag_chain.py

import chromadb
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.llms import Ollama
from langchain_chroma import Chroma
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser

def create_rag_chain():
    # Must be the same model used during ingestion
    embeddings = HuggingFaceEmbeddings(model_name=&quot;all-MiniLM-L6-v2&quot;)

    client = chromadb.HttpClient(host=&quot;chromadb&quot;, port=8000)
    vectorstore = Chroma(
        client=client,
        collection_name=&quot;documentation&quot;,
        embedding_function=embeddings
    )

    # Retrieve top 3 most relevant chunks
    retriever = vectorstore.as_retriever(
        search_type=&quot;similarity&quot;,
        search_kwargs={&quot;k&quot;: 3}
    )

    llm = Ollama(
        base_url=&quot;http://ollama:11434&quot;,
        model=&quot;llama3&quot;,
        temperature=0.3,
        num_predict=250   # Cap response length — critical on CPU
    )

    template = &quot;&quot;&quot;You are a technical support assistant.
Answer ONLY from the provided context. Cite your source.
If the answer is not in the context, say so clearly.

Context: {context}
Question: {question}
Answer:&quot;&quot;&quot;

    prompt = ChatPromptTemplate.from_template(template)

    def format_docs(docs):
        return &quot;\n\n&quot;.join([
            f&quot;[Source: {d.metadata.get('module', '?')}]\n{d.page_content}&quot;
            for d in docs
        ])

    # The full pipeline in 4 steps
    return (
        {&quot;context&quot;: retriever | format_docs, &quot;question&quot;: RunnablePassthrough()}
        | prompt
        | llm
        | StrOutputParser()
    )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The chain is a pipeline: &lt;code&gt;retriever → prompt → llm → parser&lt;/code&gt;. LangChain's &lt;code&gt;|&lt;/code&gt; operator makes this clean and readable. Each step passes its output to the next.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-3-api-and-interface&quot;&gt;Step 3 : API and Interface&lt;/h3&gt;
&lt;p&gt;FastAPI exposes the chain as a REST endpoint:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# src/main.py

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from rag_chain import create_rag_chain

app = FastAPI(title=&quot;Local RAG Assistant&quot;)
chain = create_rag_chain()

class QueryRequest(BaseModel):
    question: str

@app.post(&quot;/query&quot;)
def query(request: QueryRequest):
    try:
        answer = chain.invoke(request.question)
        return {&quot;question&quot;: request.question, &quot;answer&quot;: answer}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Streamlit makes it usable in a browser in 10 lines:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# src/app.py

import streamlit as st
import requests

st.title(&quot;Technical Support Assistant&quot;)
question = st.text_input(&quot;Your question:&quot;)

if st.button(&quot;Search&quot;) and question:
    with st.spinner(&quot;Searching documentation... (1-2 min on CPU)&quot;):
        r = requests.post(
            &quot;http://python-api:8000/query&quot;,
            json={&quot;question&quot;: question},
            timeout=600
        )
        st.write(r.json()[&quot;answer&quot;])
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-broke-and-how-i-fixed-it-&quot;&gt;What Broke (and How I Fixed It)&lt;/h3&gt;
&lt;p&gt;This is the part nobody writes about. Three real problems I hit.&lt;/p&gt;
&lt;h4 id=&quot;problem-1-chromadb-v2-silently-ignoring-my-data&quot;&gt;Problem 1 : ChromaDB v2 silently ignoring my data&lt;/h4&gt;
&lt;p&gt;I was connecting with the old &lt;code&gt;client_settings&lt;/code&gt; syntax:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# WRONG silently stores data locally instead of sending to the server
Chroma.from_documents(
    documents=chunks,
    client_settings=Chroma.Settings(chroma_server_host=&quot;chromadb&quot;)
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The ingestion ran without errors, showed 9669 chunks stored but ChromaDB had 0 vectors. Querying returned nothing.&lt;/p&gt;
&lt;p&gt;The fix explicit &lt;code&gt;HttpClient&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# CORRECT explicit HTTP connection to the ChromaDB Docker service
client = chromadb.HttpClient(host=&quot;chromadb&quot;, port=8000)
Chroma.from_documents(documents=chunks, client=client, ...)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also: the v1 heartbeat endpoint (&lt;code&gt;/api/v1/heartbeat&lt;/code&gt;) is deprecated. Use &lt;code&gt;/api/v2/heartbeat&lt;/code&gt; to check if ChromaDB is alive.&lt;/p&gt;
&lt;h4 id=&quot;problem-2-langchain-moved-its-modules&quot;&gt;Problem 2 : LangChain moved its modules&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Broke silently after a LangChain update
from langchain.prompts import ChatPromptTemplate           # ❌ ModuleNotFoundError
from langchain.schema.runnable import RunnablePassthrough  # ❌ ModuleNotFoundError

# Everything stable lives in langchain_core now
from langchain_core.prompts import ChatPromptTemplate      # ✅
from langchain_core.runnables import RunnablePassthrough   # ✅
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;LangChain has been refactoring aggressively across versions. If you hit &lt;code&gt;ModuleNotFoundError&lt;/code&gt;, check &lt;code&gt;langchain_core&lt;/code&gt; first it's the stable base layer they're committing to not break.&lt;/p&gt;
&lt;h4 id=&quot;problem-3-llama-3-timing-out-on-cpu&quot;&gt;Problem 3 : Llama 3 timing out on CPU&lt;/h4&gt;
&lt;p&gt;Llama 3 (8B parameters) on CPU generates roughly 2-5 tokens per second. A 200-word answer takes 2+ minutes. My 120-second timeout was too short.&lt;/p&gt;
&lt;p&gt;Three things helped significantly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dropping &lt;code&gt;k&lt;/code&gt; from 5 to 3 chunks shorter prompt = faster time-to-first-token&lt;/li&gt;
&lt;li&gt;Adding &lt;code&gt;num_predict=250&lt;/code&gt; to cap response length without it, the model generates forever&lt;/li&gt;
&lt;li&gt;Allocating more RAM to Docker via &lt;code&gt;.wslconfig&lt;/code&gt; on Windows to avoid swap&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;results&quot;&gt;Results&lt;/h3&gt;
&lt;p&gt;After setup, the assistant correctly answers questions grounded in the official documentation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&quot;How to close monthly payroll?&quot;&lt;/em&gt; → Step-by-step procedure from the HR module manual&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&quot;How to create an account in the chart of accounts?&quot;&lt;/em&gt; → Exact navigation path, source cited&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&quot;What does SYSCOHADA class 4 cover?&quot;&lt;/em&gt; → Accurate definition from the accounting reference&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And critically when the answer isn't in the documentation, it says so explicitly instead of hallucinating. That was the whole point.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;On RAG:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The embedding model used during ingestion must be &lt;strong&gt;identical&lt;/strong&gt; to the one used at query time. A different model produces incompatible vector spaces your similarity search returns garbage without any error message.&lt;/p&gt;
&lt;p&gt;Chunk size matters more than expected. 500 characters worked less well than 300 for technical documents shorter chunks produce more precise retrieval.&lt;/p&gt;
&lt;p&gt;Metadata on chunks is essential for source citation. Tag every chunk with its document name at ingestion time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On local LLMs:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Running on CPU is slow but viable for non-real-time use cases like internal support tools.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;num_predict&lt;/code&gt; is your most important parameter for performance. Without it, the model generates until it decides to stop sometimes never.&lt;/p&gt;
&lt;p&gt;Docker container networking does not use &lt;code&gt;localhost&lt;/code&gt;. Use the service name defined in &lt;code&gt;docker-compose.yml&lt;/code&gt; (e.g., &lt;code&gt;chromadb&lt;/code&gt;, &lt;code&gt;ollama&lt;/code&gt;) as the hostname when connecting between containers.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;This project is available on my github : &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/josaphatstar/Assistant-Intelligent-RAG&quot;&gt;https://github.com/josaphatstar/Assistant-Intelligent-RAG&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-s-next&quot;&gt;What's Next&lt;/h3&gt;
&lt;p&gt;This RAG pipeline handles straightforward questions well. But it has a core limitation: &lt;strong&gt;it always does the same thing&lt;/strong&gt; regardless of the question type. Whether you ask a procedural question or report a system crash, it searches the docs and answers. No reasoning about what strategy fits best.&lt;/p&gt;
&lt;p&gt;In the next article, I'll show how I evolved this into an &lt;strong&gt;Agentic AI architecture&lt;/strong&gt; with LangGraph where the system first &lt;em&gt;decides&lt;/em&gt; which agent to call (documentation search, error diagnosis, or human escalation ticket), then acts accordingly.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I'm a Master's student in AI &amp;amp; Big Data, and this project came out of a real internship constraint no cloud, no API keys, just local infrastructure and open-source tools. I'm curious: have you built a local RAG pipeline under similar constraints? What stack did you use, and what broke first? Drop it in the comments I'd genuinely like to compare notes.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/23449/i-built-a-local-rag-assistant-with-ollama-chromadb-and-langchain</guid>
<pubDate>Sat, 25 Jul 2026 14:42:23 +0000</pubDate>
</item>
<item>
<title>LangChain Components</title>
<link>https://coderlegion.com/22206/langchain-components</link>
<description>&lt;p&gt;&lt;strong&gt;What are LangChain Components?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;LangChain Components are the individual building blocks provided by LangChain that work together to create AI-powered applications. Each component performs a specific task, such as generating responses, managing memory, retrieving information, using tools, or processing documents.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/13ugfsk7vd3wgf2okeib.jpeg&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.Models**&lt;/strong&gt;:Core interfaces through which U interact with AI models.&lt;br&gt;
This component standardizes the interface to communicate with different LLM's using their API's.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vo912pd3fnc8w6u7emtz.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.Prompts&lt;/strong&gt;: Input provided to LLM are called prompts.&lt;br&gt;
This component provides a way to manage and optimize the input given to LLMs to get the best possible output.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Types of Prompts&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Dynamic and Reusable&lt;/strong&gt;: Templates that let you swap variables (like names or data) without rewriting the core instruction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Role-based&lt;/strong&gt; : Assigning a specific persona to the AI (e.g., &quot;You are an expert coder&quot;) to guide the style of its response.&lt;br&gt;
3.&lt;strong&gt; Few-Shot Prompting&lt;/strong&gt; : Providing a few examples of input and output to help the AI understand the pattern you want it to follow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;3.Chains:&lt;/strong&gt;Used to build pipelines.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Parallel Chains&lt;/strong&gt;: Run multiple models or processes at the same time to gather information, which is then combined into a single output.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conditional Chains&lt;/strong&gt;: Use logic to determine the next step in the process. For example, an AI agent can analyze feedback and decide between different paths (like sending a &quot;Thank You&quot; or an &quot;Email&quot; based on the result).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hmj66npr8jopm76mmsqj.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4.Indexes&lt;/strong&gt;: Connect your application to external knowledge such as PDFs, websites, or databases.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i4fbbz62dc01e3yb6aei.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Doc Loader: Imports your data from various sources.&lt;/li&gt;
&lt;li&gt;Text Splitter: Breaks large documents into smaller, manageable pieces.&lt;/li&gt;
&lt;li&gt;Vector Store: Saves those pieces in a way the AI can easily search.&lt;/li&gt;
&lt;li&gt;Retrievers: The mechanism used to fetch the relevant data when a question is asked.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;5.Memory&lt;/strong&gt;: &quot;LLM API calls are &quot;stateless.&quot;&lt;br&gt;
This means the model does not remember past conversations made via API.&lt;br&gt;
With the LangChain Memory component, it can store conversations, allowing the AI to keep track of context over time.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8btg07wedpjluxdo67yi.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6.Agents&lt;/strong&gt;: Agents use LLMs to decide which actions to take and in what order.It is like chatbot with superpower. &lt;br&gt;
Instead of just responding, an Agent acts as a controller that uses tools (like search engines or calculators) to complete a task.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Types of Agents&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Action Agents: They execute a task, observe the result, and repeat until finished.&lt;/li&gt;
&lt;li&gt;Plan-and-Execute Agents: They create a step-by-step plan for complex problems before performing each action.&lt;/li&gt;
&lt;li&gt;ReAct Agents: They use a loop of &quot;Reasoning&quot; and &quot;Acting&quot; to think through a task, pick a tool, and adjust based on observations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Check the previous blog on LangChain Introduction. &lt;br&gt;
 &lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/knitisha/what-is-langchain-a-detailed-explanation-4dkk&quot;&gt;https://dev.to/knitisha/what-is-langchain-a-detailed-explanation-4dkk&lt;/a&gt; &lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22206/langchain-components</guid>
<pubDate>Fri, 10 Jul 2026 08:21:42 +0000</pubDate>
</item>
<item>
<title>What is LangChain? A Detailed Explanation</title>
<link>https://coderlegion.com/22205/what-is-langchain-a-detailed-explanation</link>
<description>&lt;p&gt;&lt;strong&gt;LangChain&lt;/strong&gt; is a powerful framework that solves a major headache in AI development: vendor lock-in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why LangChain?&lt;/strong&gt;&lt;br&gt;
When you build an application by calling an LLM's API directly (like OpenAI's GPT or Google's Gemini), your code becomes tightly coupled to that specific provider. If you decide to switch models ,perhaps to save money, improve performance, or move to an open-source model you often have to rewrite the entire &quot;plumbing&quot; of your application, from how prompts are formatted to how responses are parsed.  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How LangChain Solves This&lt;/strong&gt;&lt;br&gt;
LangChain acts as a standardized interface (or abstraction layer). Instead of your code talking directly to a specific LLM, it talks to LangChain's generic &quot;LLM&quot; component.&lt;/p&gt;
&lt;p&gt;Think of it like an electrical plug. Instead of hard-wiring your appliance to the wall, you use a universal outlet. Whether the power comes from a coal plant, a solar farm, or a wind turbine (the different LLM providers), your appliance stays the same.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Without LangChain:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Direct API: Rigid and hard to change
from openai import OpenAI

client = OpenAI(api_key=&quot;your_key&quot;)

def ask_model(question):
    # This structure is specific only to OpenAI
    response = client.chat.completions.create(
        model=&quot;gpt-4&quot;,
        messages=[{&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: question}]
    )
    return response.choices[0].message.content

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The &quot;Magic&quot; of the Standard Interface :&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In LangChain, every model provider (OpenAI, Anthropic, Google, Llama) implements the same standard methods. Because they all &quot;speak the same language&quot; to your code&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;You don't change your logic&lt;/strong&gt;: Your core application code—the part that manages memory, prompt templates, and chains—remains identical.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minimal configuration changes&lt;/strong&gt;: To switch from GPT-4 to Claude or a local Llama model, you typically only need to change one line of initialization code where you define the model object&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rapid Experimentation&lt;/strong&gt;: You can test three different models against your application in minutes just by swapping the model name in your configuration, rather than refactoring your entire codebase.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;The Power of Abstraction&lt;/strong&gt;&lt;br&gt;
When you use LangChain, you are using abstractions. An abstraction simplifies complex code by representing a process as a named component&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Prompt Templates&lt;/strong&gt;: Instead of hard-coding strings, you use a template object that stays the same regardless of which LLM you use. &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unified Methods&lt;/strong&gt;: You use functions like .invoke() or .stream() for every model. Under the hood, LangChain translates these into the specific API calls required by the provider you selected.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;With LangChain&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from langchain_openai import ChatOpenAI

# You only change this object to swap models (e.g., to Anthropic or Llama)
llm = ChatOpenAI(model=&quot;gpt-4&quot;, api_key=&quot;your_key&quot;)

def ask_model(question):
    # .invoke() works the same way regardless of the model chosen
    response = llm.invoke(question)
    return response.content

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For more info:&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.langchain.com/&quot;&gt;https://docs.langchain.com/&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Check this for next imporant topic: LangChain Components&lt;/strong&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/knitisha/langchain-components-2ekd&quot;&gt;https://dev.to/knitisha/langchain-components-2ekd&lt;/a&gt;&lt;br&gt;
I know this was a bit of a long read, but I'm confident that by now you have a solid understanding of what LangChain is and why it's so useful.&lt;br&gt;
If you found this blog helpful, please leave a &lt;strong&gt;like&lt;/strong&gt; and let me know in the &lt;strong&gt;comments&lt;/strong&gt; if the explanation was easy to understand. &lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22205/what-is-langchain-a-detailed-explanation</guid>
<pubDate>Fri, 10 Jul 2026 08:21:01 +0000</pubDate>
</item>
<item>
<title>Memory in LLM Agents, Explained: From Stateless Calls to Long-Term Memory</title>
<link>https://coderlegion.com/21074/memory-in-llm-agents-explained-from-stateless-calls-to-long-term-memory</link>
<description>&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;
&lt;p&gt;Most explanations of agent memory start at the wrong altitude. They jump straight to &quot;use a vector database&quot; without explaining what problem that solves, or why a vector database is sometimes the wrong tool entirely.&lt;/p&gt;
&lt;p&gt;This post walks through memory the way I built it: as a progression of seven small, runnable scripts, starting from a completely stateless LLM call and ending at a two-layer system with separate short-term and long-term memory. Each step introduces exactly one new concept. By the end, the line between short-term and long-term memory stops being fuzzy and becomes a concrete architectural decision: what is scoped to a thread, and what is scoped to a user.&lt;/p&gt;
&lt;p&gt;All code referenced here is in the open-source repo at the end of this post. Every script is self-contained and runnable on its own.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;1-stateless-the-baseline-problem&quot;&gt;1. Stateless: the baseline problem&lt;/h3&gt;
&lt;p&gt;The simplest possible setup is a single call to an LLM with no history attached. Tell it your name, ask it your name in the next message, and it has no idea. Every call starts from zero.&lt;/p&gt;
&lt;p&gt;This is not a bug. It is the literal absence of memory, and it is the baseline every other pattern in this guide is solving for.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;2-short-term-memory-in-ram&quot;&gt;2. Short-term memory in RAM&lt;/h3&gt;
&lt;p&gt;The most direct fix: keep the full conversation in a Python list, and send that list with every call to the model.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;history.append({&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: user_input})
response = llm.invoke(history)
history.append({&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: response.content})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the model can recall earlier turns, because it is literally being shown them every time. The catch: this history lives in process memory. Restart the script and it is gone. This pattern is memory in the loosest sense, useful for a single uninterrupted session, useless across sessions.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;3-persistence-and-threads&quot;&gt;3. Persistence and threads&lt;/h3&gt;
&lt;p&gt;The next step is durability. Write the conversation history to SQLite after every turn, and reload it on startup.&lt;/p&gt;
&lt;p&gt;This alone solves the restart problem. The second piece is the thread_id: rather than one global history, each thread_id is its own isolated conversation. Multiple conversations can live in the same store without bleeding into each other, and you can switch between them on demand.&lt;/p&gt;
&lt;p&gt;At this point memory has gone from &quot;exists only while the process is running&quot; to &quot;exists independently of the process, scoped to a conversation.&quot;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;4-sliding-window&quot;&gt;4. Sliding window&lt;/h3&gt;
&lt;p&gt;A real conversation grows without bound, and sending the full history on every call gets expensive fast, both in tokens and in latency. The sliding window pattern fixes the cost problem directly: a &lt;code&gt;@before_model&lt;/code&gt; middleware hook trims the stored history down to the last N messages right before every call to the model.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;@before_model
def trim_to_window(messages):
    return messages[-WINDOW:]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Token cost is now bounded, regardless of how long the conversation runs. The tradeoff is blunt: anything said more than N turns ago is permanently inaccessible to the model. If the user mentioned an important constraint 10 turns ago and the window is 4, that constraint is gone.&lt;/p&gt;
&lt;p&gt;This is the right tool when recent context is what matters and the conversation is expected to be short or self-contained.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;5-summarization&quot;&gt;5. Summarization&lt;/h3&gt;
&lt;p&gt;Summarization is the more graceful version of the same idea. Instead of discarding old messages outright, a &lt;code&gt;@before_model&lt;/code&gt; middleware hook compresses them into a short summary once the stored message count crosses a threshold, while keeping the most recent few messages verbatim alongside that summary.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;@before_model
def summarize_if_needed(messages):
    if len(messages) &amp;gt; SUMMARIZE_AFTER:
        old, recent = messages[:-KEEP_RECENT], messages[-KEEP_RECENT:]
        summary = llm.invoke([SUMMARY_PROMPT, *old])
        return [summary_message(summary), *recent]
    return messages
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This retains the gist of everything that happened earlier in the conversation, at the cost of losing fine-grained detail. A sliding window would have kept the literal text of the last N turns and nothing before that; summarization keeps a compressed signal of everything before that, plus the literal text of the most recent few turns.&lt;/p&gt;
&lt;p&gt;Neither pattern is strictly better. Sliding window is cheaper and simpler. Summarization preserves more of the conversation's shape, at the cost of an extra LLM call to generate the summary.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;6-long-term-memory-the-user-profile&quot;&gt;6. Long-term memory: the user profile&lt;/h3&gt;
&lt;p&gt;Every pattern so far is still short-term memory. It lives within one conversation thread and, even with persistence, none of it is shared if the user starts a different thread.&lt;/p&gt;
&lt;p&gt;Long-term memory is a different scope entirely: durable facts about a user that should be available no matter which conversation they are currently having. The pattern here uses a second LLM call after every turn to extract durable facts (name, job, stated preferences) and write them to a key-value store (LangGraph's &lt;code&gt;SqliteStore&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;facts = extract_facts_llm.invoke([extraction_prompt, *recent_turns])
store.put(namespace=(&quot;user&quot;, user_id), key=&quot;profile&quot;, value=facts)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On the next session, even a completely separate thread, those facts are loaded from the store and injected into the system prompt. This is the first pattern in the series where memory survives across sessions that have no shared conversation history at all.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;7-combining-short-term-and-long-term-memory&quot;&gt;7. Combining short-term and long-term memory&lt;/h3&gt;
&lt;p&gt;The full architecture uses both layers together, each with a different scope:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Short-term memory&lt;/strong&gt;, via &lt;code&gt;SqliteSaver&lt;/code&gt;: conversation history, scoped to a &lt;code&gt;thread_id&lt;/code&gt;. Restored automatically on reconnect to the same thread.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Long-term memory&lt;/strong&gt;, via &lt;code&gt;SqliteStore&lt;/code&gt;: durable behavioral rules, scoped to a &lt;code&gt;user_id&lt;/code&gt;. The agent saves rules autonomously via a &lt;code&gt;save_rule&lt;/code&gt; tool, and those rules apply to every future session for that user, regardless of thread.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The clarifying detail: open a new thread for the same user, and the conversation history resets, but the rules that user taught the agent in a previous thread are already active. Switch to a different user entirely, and that user inherits none of the first user's rules. Each user's long-term memory is fully isolated.&lt;/p&gt;
&lt;p&gt;This is the insight that took the fuzziness out of &quot;short-term vs long-term memory&quot; for me. They are not the same kind of memory at different durations. They are scoped along different dimensions: STM resets per thread, LTM persists per user across every thread that user ever opens.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;choosing-a-pattern&quot;&gt;Choosing a pattern&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Situation &lt;/th&gt;&lt;th&gt;Pattern&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Single-session prototype, no persistence needed &lt;/td&gt;&lt;td&gt;STM in RAM&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Conversation needs to survive restarts &lt;/td&gt;&lt;td&gt;STM plus SQLite with threads&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Long conversations, recent context matters most, cost-sensitive &lt;/td&gt;&lt;td&gt;Sliding window&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Long conversations, full context shape matters &lt;/td&gt;&lt;td&gt;Summarization&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Facts about the user should persist across sessions &lt;/td&gt;&lt;td&gt;Long-term memory, user profile&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Production agent with both ongoing conversations and persistent user behavior &lt;/td&gt;&lt;td&gt;STM and LTM combined&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;further-reading&quot;&gt;Further reading&lt;/h3&gt;
&lt;p&gt;This series draws directly on LangChain and LangGraph's memory primitives. For the underlying API reference:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.langchain.com/oss/python/langchain/short-term-memory&quot;&gt;LangChain short-term memory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.langchain.com/oss/python/langchain/short-term-memory#before-model&quot;&gt;Before-model middleware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.langchain.com/oss/python/langchain/middleware/overview&quot;&gt;Middleware overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.langchain.com/oss/python/langchain/short-term-memory#summarize-messages&quot;&gt;Message summarization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.langchain.com/oss/python/langchain/long-term-memory&quot;&gt;LangChain long-term memory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.langchain.com/oss/python/langgraph/stores&quot;&gt;LangGraph stores&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Memory in LLM applications is not one feature, it is a set of independent tradeoffs: durability versus simplicity, recall versus token cost, thread-scoped versus user-scoped. Building each pattern in isolation, in order, makes those tradeoffs visible rather than hidden behind a single &quot;add memory&quot; abstraction.&lt;/p&gt;
&lt;p&gt;Full source, all 7 scripts, self-contained and runnable: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/f2015537/llm-memory-patterns&quot;&gt;https://github.com/f2015537/llm-memory-patterns&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/21074/memory-in-llm-agents-explained-from-stateless-calls-to-long-term-memory</guid>
<pubDate>Sun, 21 Jun 2026 08:23:59 +0000</pubDate>
</item>
<item>
<title>Chunking vs Retrieval: A RAG Case Study on a Real Codebase</title>
<link>https://coderlegion.com/20568/chunking-vs-retrieval-a-rag-case-study-on-a-real-codebase</link>
<description>&lt;h3 id=&quot;introduction-1&quot;&gt;Introduction&lt;/h3&gt;
&lt;p&gt;Most RAG discussions treat chunking and retrieval as separate concerns. Pick a chunk size, pick a retriever, tune k, done. What is less discussed is how much these decisions interact - specifically, how a bad chunking strategy can make retrieval irrelevant before it even runs.&lt;/p&gt;
&lt;p&gt;This case study runs the same three questions through four different RAG configurations on the same Python codebase. Semantic RAG with character chunking, semantic RAG with AST-based chunking, lexical RAG with BM25, and hybrid RAG with Reciprocal Rank Fusion. Same LLM. Same codebase. Only the chunking strategy or retrieval method changes.&lt;/p&gt;
&lt;p&gt;The finding: chunking strategy mattered more than retrieval strategy. AST-based chunking won or tied on every query. The retrieval method only became decisive after bad chunking had already destroyed the relevant context.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-setup&quot;&gt;The setup&lt;/h3&gt;
&lt;p&gt;The target codebase is a small Python task-management application with auth, permissions, billing, notifications, audit logging, and a recurring-task scheduler. Thirteen files. Realistic enough to produce interesting retrieval failures.&lt;/p&gt;
&lt;p&gt;Every agent is built the same way: a LangChain agent with a single search_codebase tool, instructed to always search before answering and to cite specific files and functions.&lt;/p&gt;
&lt;p&gt;Three questions were chosen to stress different aspects of retrieval:&lt;/p&gt;
&lt;p&gt;Q1 tests whether a permission rule documented only in a docstring survives chunking.&lt;br&gt;
Q2 tests the lexical gap: the question uses different vocabulary from the code.&lt;br&gt;
Q3 tests exact identifier lookup, the easiest case for any retriever.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-four-strategies&quot;&gt;The four strategies&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Script 1: Semantic RAG, character-based chunking&lt;/strong&gt;&lt;br&gt;
RecursiveCharacterTextSplitter at 256 chars / 32 overlap. OpenAI embeddings. Chroma vector store. 173 chunks from 13 files. This is the baseline most RAG tutorials implement.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Script 3: Semantic RAG, AST-based chunking&lt;/strong&gt;&lt;br&gt;
Python's ast module parses each file into a syntax tree. Each top-level class or function becomes one chunk - signature, docstring, and body together. 28 chunks from the same 13 files. Far fewer, far larger, semantically coherent units.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Script 5: Lexical RAG, BM25&lt;/strong&gt;&lt;br&gt;
Same character-based chunks as Script 1 (173 chunks), retrieved with rank_bm25 instead of embeddings. No vector store. No embedding API calls.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Script 6: Hybrid RAG, Reciprocal Rank Fusion&lt;/strong&gt;&lt;br&gt;
LangChain EnsembleRetriever fusing semantic and BM25 retrievers at equal weights. Same character-based chunks. RRF re-ranks by combining the ranked lists from both retrievers.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;results-1&quot;&gt;Results&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Strategy &lt;/th&gt;&lt;th&gt;Q1: docstring permission &lt;/th&gt;&lt;th&gt;Q2: vocabulary mismatch &lt;/th&gt;&lt;th&gt;Q3: exact identifier&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Semantic, char-chunked &lt;/td&gt;&lt;td&gt;Hedged &lt;/td&gt;&lt;td&gt;Correct &lt;/td&gt;&lt;td&gt;Correct&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Semantic, AST-chunked &lt;/td&gt;&lt;td&gt;Correct, confident &lt;/td&gt;&lt;td&gt;Correct, detailed &lt;/td&gt;&lt;td&gt;Correct&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Lexical BM25 &lt;/td&gt;&lt;td&gt;Failed &lt;/td&gt;&lt;td&gt;Failed &lt;/td&gt;&lt;td&gt;Correct&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Hybrid RRF &lt;/td&gt;&lt;td&gt;Failed &lt;/td&gt;&lt;td&gt;Correct &lt;/td&gt;&lt;td&gt;Correct&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;q1-the-docstring-question&quot;&gt;Q1: The docstring question&lt;/h3&gt;
&lt;p&gt;The answer (&quot;admin only&quot;) lives entirely in the docstring of TaskService.assign_task:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def assign_task(self, token: str, task_id: int, assignee_id: int) -&amp;gt; Task:
    &quot;&quot;&quot;
    Reassign a task to another user.
    Requires task:assign permission (admin only).
    &quot;&quot;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With 256-char chunking, this docstring and the surrounding permission logic are split across multiple character windows, mixed with fragments from main.py seed data and database.py helpers. The embedding retriever returned chunks that mention assignment but never the docstring itself. The agent hedged: &quot;may be admin-only, but not definitively stated.&quot;&lt;/p&gt;
&lt;p&gt;BM25 and hybrid fared worse. Their top chunks were dominated by unrelated auth.py text, and both returned &quot;I could not find that in the codebase.&quot;&lt;/p&gt;
&lt;p&gt;With AST-based chunking, the entire TaskService class including that docstring is one chunk. The retriever returns it directly. The agent quotes the docstring verbatim and answers with full confidence.&lt;/p&gt;
&lt;p&gt;This is a chunking effect, not a retrieval effect. The retriever in Script 1 was not wrong - it returned the most semantically similar character windows. The relevant information had simply been destroyed by the chunking step before retrieval ran.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;q2-the-lexical-gap-question&quot;&gt;Q2: The lexical gap question&lt;/h3&gt;
&lt;p&gt;&quot;If a teammate's work gets handed off to someone else, how do they find out?&quot;&lt;/p&gt;
&lt;p&gt;The code says &quot;assignee&quot; and &quot;on_task_assigned&quot;. The question says &quot;teammate&quot; and &quot;handed off&quot;. These share almost no tokens.&lt;/p&gt;
&lt;p&gt;BM25 matched on &quot;task&quot; and &quot;find&quot; and returned irrelevant auth.py and integrations chunks. It has no way to bridge the gap between &quot;handed off&quot; and &quot;on_task_assigned&quot; without semantic understanding. Result: failed.&lt;/p&gt;
&lt;p&gt;Both embedding retrievers found the correct chunk because &quot;hand off work to a teammate&quot; and &quot;assign a task to a user&quot; are close in embedding space even without shared vocabulary. The semantic representation captures the conceptual similarity that lexical matching cannot.&lt;/p&gt;
&lt;p&gt;Hybrid RRF also succeeded. Its semantic half compensated for its BM25 half, pulling the correct chunk into the top-k results.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;q3-the-exact-identifier-question&quot;&gt;Q3: The exact identifier question&lt;/h3&gt;
&lt;p&gt;&quot;What exception does check_task_limit raise, and when?&quot;&lt;/p&gt;
&lt;p&gt;Every strategy got this right. When the query contains the literal function name from the code, BM25's exact term matching is as effective as embeddings and far cheaper - no embedding API calls required.&lt;/p&gt;
&lt;p&gt;This is BM25's strongest use case: exact identifier lookups, error string searches, config key lookups. For these queries, adding a semantic retriever adds cost without adding quality.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;metrics-the-precision-recall-tradeoff&quot;&gt;Metrics: the precision/recall tradeoff&lt;/h3&gt;
&lt;p&gt;Script 7 runs a golden set of 6 queries with known-relevant documents against an InMemoryVectorStore at k values of 1, 3, and 5:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;k &lt;/th&gt;&lt;th&gt;Recall &lt;/th&gt;&lt;th&gt;Precision &lt;/th&gt;&lt;th&gt;MRR &lt;/th&gt;&lt;th&gt;nDCG&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1 &lt;/td&gt;&lt;td&gt;0.667 &lt;/td&gt;&lt;td&gt;0.833 &lt;/td&gt;&lt;td&gt;0.833 &lt;/td&gt;&lt;td&gt;0.833&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3 &lt;/td&gt;&lt;td&gt;0.917 &lt;/td&gt;&lt;td&gt;0.444 &lt;/td&gt;&lt;td&gt;0.917 &lt;/td&gt;&lt;td&gt;1.000&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;5 &lt;/td&gt;&lt;td&gt;1.000 &lt;/td&gt;&lt;td&gt;0.300 &lt;/td&gt;&lt;td&gt;0.917 &lt;/td&gt;&lt;td&gt;0.942&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Recall climbs toward 1.0 as k grows. Precision falls. This is the expected tradeoff: retrieving more chunks eventually finds every relevant document, but an increasing share of retrieved chunks are irrelevant noise the LLM has to filter out.&lt;/p&gt;
&lt;p&gt;The failure at k=3 flags one query whose answer requires synthesising information from two documents. Only one of the two was retrieved. This is a common failure mode in RAG: questions that need multi-document synthesis are harder than questions with a single-document answer.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-decision-framework&quot;&gt;The decision framework&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Use case &lt;/th&gt;&lt;th&gt;Strategy &lt;/th&gt;&lt;th&gt;Reason&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Conceptual questions about code: permissions, contracts, design intent &lt;/td&gt;&lt;td&gt;AST-based chunking &lt;/td&gt;&lt;td&gt;Keeps function signature, docstring, and body as one retrievable unit&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Exact identifier / error string / config key lookup &lt;/td&gt;&lt;td&gt;BM25 lexical &lt;/td&gt;&lt;td&gt;Precise, fast, no embedding cost&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Mixed workload, unpredictable query types &lt;/td&gt;&lt;td&gt;Hybrid RRF &lt;/td&gt;&lt;td&gt;Semantic compensates for lexical gaps; BM25 handles exact matches&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;General prose, documentation, not source code &lt;/td&gt;&lt;td&gt;Semantic, char-chunked &lt;/td&gt;&lt;td&gt;Simple and effective when content lacks syntactic structure worth preserving&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-comes-next&quot;&gt;What comes next&lt;/h3&gt;
&lt;p&gt;The best configuration this case study points to - AST-based chunking combined with hybrid retrieval - was not wired up in this repo. It is the natural next step, and the most likely setup to handle the full range of query types the three test questions represent.&lt;/p&gt;
&lt;p&gt;tree-sitter is worth exploring as an alternative to Python's ast module for multi-language codebases. It supports the same unit-based chunking principle with broader language coverage.&lt;/p&gt;
&lt;p&gt;A larger golden set would also strengthen the metrics analysis. Six queries is enough to illustrate the precision/recall tradeoff but not enough to draw statistical conclusions about relative strategy performance.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;conclusion-1&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Chunking strategy and retrieval strategy are not independent decisions. Chunking runs first and sets the ceiling for what retrieval can possibly find. A retriever cannot return information that chunking has destroyed.&lt;/p&gt;
&lt;p&gt;For code Q&amp;amp;A, AST-based chunking raises that ceiling dramatically. The retrieval method matters most in the middle - once chunking has preserved the relevant context, and once the query's vocabulary diverges from the code's.&lt;/p&gt;
&lt;p&gt;The practical order of operations: get chunking right first. Then tune retrieval.&lt;/p&gt;
&lt;p&gt;Full source: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/f2015537/agentic-rag-case-study&quot;&gt;https://github.com/f2015537/agentic-rag-case-study&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/20568/chunking-vs-retrieval-a-rag-case-study-on-a-real-codebase</guid>
<pubDate>Sun, 14 Jun 2026 08:16:28 +0000</pubDate>
</item>
<item>
<title>ThermoMind + LangChain: Zero‑History Continuity Is Real</title>
<link>https://coderlegion.com/20058/thermomind-langchain-zero-history-continuity-is-real</link>
<description>&lt;p&gt;I just ran a fresh test of &lt;strong&gt;ThermoMind Continuity&lt;/strong&gt; wired into &lt;strong&gt;LangChain + DeepSeek&lt;/strong&gt;, and the results honestly shocked me.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I wiped all chat history. Restarted the script. &lt;br&gt;
Sent a zero-history prompt. &lt;br&gt;
No retriever. &lt;br&gt;
No vector DB. &lt;br&gt;
No cache. &lt;br&gt;
No LangChain memory.&lt;br&gt;
And the agent STILL remembered:&lt;/p&gt;
&lt;p&gt;my name&lt;br&gt;
its own agent identity&lt;br&gt;
my two cats (Pookah &amp;amp; Papo)&lt;/p&gt;
&lt;p&gt;This wasn't a trick  the LLM received zero prior messages. All continuity came from the &lt;strong&gt;thermodynamic substrate state&lt;/strong&gt;, not the model.&lt;br&gt;
The substrate woke up already knowing who it was and who I was.&lt;/p&gt;
&lt;p&gt;This is what &lt;strong&gt;persistent cognition&lt;/strong&gt; looks like.&lt;br&gt;
The integration is open source and works with any &lt;strong&gt;LangChain&lt;/strong&gt;-supported model — swap &lt;strong&gt;DeepSeek&lt;/strong&gt; for &lt;strong&gt;GPT&lt;/strong&gt;, &lt;strong&gt;Claude&lt;/strong&gt;, or &lt;strong&gt;Gemini&lt;/strong&gt;, the memory layer doesn't change.&lt;/p&gt;
&lt;p&gt;👉 SDK: &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/nile-green-ai/thermomind-continuity&quot;&gt;https://github.com/nile-green-ai/thermomind-continuity&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
</description>
<category>Discussions</category>
<guid isPermaLink="true">https://coderlegion.com/20058/thermomind-langchain-zero-history-continuity-is-real</guid>
<pubDate>Tue, 09 Jun 2026 11:44:34 +0000</pubDate>
</item>
<item>
<title>LangChain alternative for PHP developers</title>
<link>https://coderlegion.com/14321/langchain-alternative-for-php-developers</link>
<description>&lt;p&gt;Finding a viable LangChain alternative for PHP has been a journey born of necessity and frustration. As a PHP developer for over fifteen years, I've witnessed our community adapt to countless technological shifts — from the LAMP stack to the rise of frameworks like Laravel and Symfony, from monolithic applications to microservices architecture. Yet nothing has felt quite as transformative — or as potentially exclusionary — as AI Agents development.&lt;/p&gt;
&lt;p&gt;When I first began exploring the possibilities of integrating large language models into my applications, the excitement quickly disappeared. Cutting-edge tools were being built for Python, JavaScript, and Java, while PHP developers were left wondering if we'd ever catch up. LangChain emerged as the dominant framework for building AI agents, offering a comprehensive toolkit for creating sophisticated applications with LLMs. But it wasn't built for us (PHPers).&lt;/p&gt;
&lt;p&gt;The options before me seemed totally unappealing. I could abandon PHP — the language that had been my professional foundation for years — and invest countless hours learning Python's ecosystem just to access these new capabilities. Or I could resign myself to basic API calls without the rich agent capabilities that were revolutionizing application development elsewhere. Neither choice felt acceptable for the millions of websites and applications built on PHP that deserve to evolve with this technology.&lt;/p&gt;
&lt;p&gt;My frustration grew with each new AI project announcement, each new tutorial aimed at other language communities. It wasn't just about feeling left out — it was about watching a technological gap widen in real-time. While developers in other languages were creating sophisticated AI agents that could reason, use tools, and maintain memory, PHP developers were cobbling together basic integrations that barely scratched the surface of what was possible.&lt;/p&gt;
&lt;p&gt;I experimented with various approaches — wrapping Python scripts in PHP, creating microservices in other languages to handle AI functionality, even attempting to port portions of LangChain's functionality directly. None of these solutions felt native or sustainable. They were compromises that introduced unnecessary complexity and technical debt.&lt;/p&gt;
&lt;p&gt;What I needed — what our entire community needed — was a framework built from the ground up for PHP developers. Something that embraced PHP's strengths rather than treating the language as a limitation. Something that would give us the same capabilities as LangChain and other full featured frameworks, but with API patterns and paradigms that felt natural to PHP developers.&lt;/p&gt;
&lt;p&gt;This realization was the genesis of Neuron AI. What began as a personal project to solve my own development challenges gradually evolved into something much more ambitious: creating the first professional-grade framework for building AI agents in PHP. &lt;/p&gt;
&lt;p&gt;The journey wasn't easy. LLM technology is complex, and creating abstractions that are both powerful and intuitive requires countless iterations. There were moments of doubt when I wondered if the effort was worth it, if PHP developers would even care about these capabilities.&lt;/p&gt;
&lt;p&gt;But with each component that fell into place — agents, memory systems, tool integrations, Structured Output — I became increasingly convinced that this work wasn't just necessary but transformative. PHP powers over 75% of websites with known server-side languages. The idea that this vast ecosystem would struggle in AI development seemed not just unfortunate but ultimately untenable.&lt;/p&gt;
&lt;p&gt;Today, Neuron AI stands as a true LangChain alternative for PHP — not a pale imitation or a simplified wrapper, but a full-featured framework designed specifically for the PHP ecosystem. It brings all the core capabilities that have made LangChain so powerful — structured agent development, memory management, tool use, structured output, MCP connections — into a package that feels natural and intuitive for PHP developers.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.neuron-ai.dev&quot;&gt;https://docs.neuron-ai.dev&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The framework represents an invitation to PHP developers everywhere: you don't have to choose between the language you know and the AI capabilities you want. You can have both.&lt;/p&gt;
&lt;p&gt;In the following sections, I'll walk through the core components of Neuron AI, demonstrate how it compares to LangChain, and show you how to build your first AI agent using this framework. Whether you're a seasoned PHP developer curious about AI or someone actively searching for a LangChain alternative in the PHP ecosystem, my hope is that you'll finish this article not just with new technical knowledge, but with a renewed sense of possibility about what you can build with the language you already know.&lt;/p&gt;
&lt;h3 id=&quot;neuron-ai-vs-langchain-a-php-developers-advantage&quot;&gt;Neuron AI vs. LangChain: A PHP Developers Advantage&lt;/h3&gt;
&lt;p&gt;When I first set out to create Neuron, what emerged wasn't just a PHP port of LangChain concepts, but a framework that leverages PHP's inherent strengths to deliver capabilities that feel natural and powerful in our ecosystem.&lt;/p&gt;
&lt;p&gt;Neuron AI stands shoulder-to-shoulder with LangChain in core functionality while bringing distinct advantages through its PHP-native implementation. Like LangChain, it provides the essential building blocks for sophisticated AI agents: chat history management, memory systems, structured output handling, function calling, vector stores, and embeddings. But the way these components are implemented makes all the difference for PHP developers.&lt;/p&gt;
&lt;h3 id=&quot;chat-history-amp-memory&quot;&gt;Chat History &amp;amp; Memory&lt;/h3&gt;
&lt;p&gt;The framework's Chat History and Memory components showcase this philosophy perfectly. While the concepts mirror LangChain's approach, Neuron's implementation automatically handles context window management — a critical consideration when working with token-limited models. The system intelligently prunes conversation history when approaching token limits, ensuring your agents remain coherent across long interactions without manual intervention. &lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.neuron-ai.dev/chat-history-and-memory&quot;&gt;https://docs.neuron-ai.dev/chat-history-and-memory&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;streaming&quot;&gt;Streaming&lt;/h3&gt;
&lt;p&gt;Streaming support represents another good point. Neuron implements streaming using generators in a way that feels natural within PHP applications.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.neuron-ai.dev/streaming&quot;&gt;https://docs.neuron-ai.dev/streaming&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;structured-output&quot;&gt;Structured Output&lt;/h3&gt;
&lt;p&gt;The ability to have LLMs return data in specific formats — is crucial for data extraction, or to integrate your AI Agent as part of a workflow that requires integration with downstream systems. Neuron AI provides robust parsers that can extract structured data from model outputs, transforming free-text responses into typed PHP objects. This capability becomes even more powerful when combined with PHP 8's type system, creating a bridge between the probabilistic world of LLMs and the type-safe world of modern PHP development.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.neuron-ai.dev/advanced/structured-output&quot;&gt;https://docs.neuron-ai.dev/advanced/structured-output&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;tool-amp-function-calls&quot;&gt;Tool &amp;amp; Function Calls&lt;/h3&gt;
&lt;p&gt;Tool and function calling capabilities in Neuron AI allow your agents to interact with external systems and APIs. Whether retrieving data from databases, calling web services, or executing custom business logic, these features let you build agents that aren't limited to text generation but can take concrete actions in response to user inputs. The implementation elegantly leverages PHP's reflection capabilities, making it simple to expose your existing PHP methods as tools for your AI agents.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.neuron-ai.dev/tools-and-function-calls&quot;&gt;https://docs.neuron-ai.dev/tools-and-function-calls&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;retrieval-augmented-generation-rag-&quot;&gt;Retrieval Augmented Generation (RAG)&lt;/h3&gt;
&lt;p&gt;For knowledge retrieval and semantic search, Neuron AI includes comprehensive support for vector stores and embeddings. These components enable agents to access relevant information from large document collections, effectively expanding their knowledge beyond what was included in their training data. The framework offers adapters for popular vector databases and embedding models, making it straightforward to implement retrieval-augmented generation (RAG) patterns in your PHP applications.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.neuron-ai.dev/rag&quot;&gt;https://docs.neuron-ai.dev/rag&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;switch-between-multiple-ai-providers-with-no-refactoring&quot;&gt;Switch Between multiple AI providers with no refactoring&lt;/h3&gt;
&lt;p&gt;Perhaps most importantly for many production environments, Neuron AI provides compatibility with a wide range of LLM providers. From commercial APIs like OpenAI and Anthropic to open-source options running locally through Ollama, the framework gives you flexibility in choosing the right models for your specific needs and constraints. This provider-agnostic approach prevents vendor lock-in and allows you to adapt as the LLM landscape evolves.&lt;/p&gt;
&lt;h3 id=&quot;observability-neuron-ai-s-native-integration-with-inspector-dev&quot;&gt;Observability: Neuron AI's Native Integration with Inspector.dev&lt;/h3&gt;
&lt;p&gt;One of the most significant challenges I encountered when building AI applications was observability—understanding what's happening inside my AI agents during execution. Traditional debugging approaches often fall short with LLM-powered systems, where the flow of information and decision-making process can be complex and opaque. This is where Neuron AI's native integration with Inspector.dev has been transformative for my development workflow. Inspector.dev, a real-time monitoring platform built specifically for PHP applications, plugs seamlessly into the Neuron framework to provide full visibility into AI agent operations. Every prompt sent to an LLM, every reasoning step, and every tool call is automatically captured and visualized in Inspector's intuitive timeline view. &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/31s874iyofjay4k1641q.png&quot; alt=&quot;Inspector Neuron AI Agent observability&quot;&gt;&lt;/p&gt;
&lt;p&gt;The ability to see inside the &quot;black box&quot; of LLM interactions not only accelerates the development process but gives you the confidence to deploy sophisticated AI agents in mission-critical applications.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.neuron-ai.dev/advanced/observability&quot;&gt;https://docs.neuron-ai.dev/advanced/observability&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;the-object-oriented-advantage&quot;&gt;The Object-Oriented Advantage&lt;/h3&gt;
&lt;p&gt;Interfaces and abstract classes provide clear contracts between components, ensuring that custom implementations will work correctly with the rest of the framework. This approach enables you to extend Neuron AI for specialized needs while maintaining compatibility with the ecosystem. PHP's strong typing capabilities, particularly in versions 8 and above, reinforce these contracts and help catch integration issues early in the development process.&lt;/p&gt;
&lt;p&gt;The framework's careful use of namespaces organizes functionality in a way that prevents conflicts and makes the API intuitive to navigate. Rather than the flat module structure common in Python libraries, Neuron AI uses PHP's namespace system to create a hierarchical organization that scales well as the framework expands.&lt;/p&gt;
&lt;p&gt;Error handling in Neuron AI takes advantage of PHP's exception system, providing clear, typed exceptions that help you quickly identify and address issues in your agent implementations. &lt;/p&gt;
&lt;h3 id=&quot;implement-your-first-agent-ai-agent-summarizing-youtube-video&quot;&gt;Implement Your First Agent: AI Agent summarizing YouTube video&lt;/h3&gt;
&lt;p&gt;Using PHP and the &lt;a rel=&quot;nofollow&quot; href=&quot;https://neuron-ai.dev&quot;&gt;Neuron AI framework&lt;/a&gt; as the foundation, I built an AI agent in PHP that automatically summarizes YouTube videos, extracting the essential information and takeaways.&lt;/p&gt;
&lt;p&gt;The agent processes video transcripts, identifies key points, and generates concise summaries that retain the core message of the original video.&lt;/p&gt;
&lt;p&gt;Let’s explore three real-world contexts where YouTube video summarization can be incredibly helpful.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Educational Context&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Students, teachers, and researchers often need to extract key information from lengthy educational content. The YouTube Agent could help:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Students can quickly determine if a 2-hour lecture contains the specific topic they’re researching.  &lt;/li&gt;
&lt;li&gt;Teachers can preview educational content before assigning it to students, ensuring relevance and quality.  &lt;/li&gt;
&lt;li&gt;Researchers can efficiently process multiple conference presentations without watching them in full.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Content Creation and Media Monitoring&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Creators and media professionals can use this Agent to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Journalists can quickly analyze trending video discussions without full viewing.  &lt;/li&gt;
&lt;li&gt;Content creators can automate description generation for their contents.  &lt;/li&gt;
&lt;li&gt;Social media managers can automate posts generation from YouTube videos ensuring more relevant content creation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just to give you some inspiration.&lt;/p&gt;
&lt;p&gt;Here is the full article on how to create this agent:&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://inspector.dev/php-ai-agent-summarizing-youtube-videos/&quot;&gt;https://inspector.dev/php-ai-agent-summarizing-youtube-videos/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here is the GitHub repository:&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/inspector-apm/youtube-ai-agent&quot;&gt;https://github.com/inspector-apm/youtube-ai-agent&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/14321/langchain-alternative-for-php-developers</guid>
<pubDate>Thu, 09 Apr 2026 10:24:19 +0000</pubDate>
</item>
<item>
<title>OCI Generative AI and LangChain: Building Enterprise AI Applications with Oracle</title>
<link>https://coderlegion.com/10026/oci-generative-ai-and-langchain-building-enterprise-ai-applications-with-oracle</link>
<description>&lt;p&gt;Integrating Oracle Cloud Infrastructure (OCI) Generative AI with LangChain unlocks powerful capabilities for building enterprise-grade AI applications. This comprehensive guide explores the official integration, demonstrates practical implementations, and shows how Oracle Database 23ai complements LangChain workflows for complete end-to-end AI solutions.&lt;/p&gt;
&lt;h3 id=&quot;what-is-langchain-&quot;&gt;What is LangChain?&lt;/h3&gt;
&lt;p&gt;LangChain is a powerful, open-source framework for developing applications powered by large language models (LLMs). It provides essential tools for managing workflows, maintaining context, and integrating with external systems, streamlining the development of AI-powered applications.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Capabilities:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;LangChain acts as a bridge, connecting LLMs with other data sources and tools, dramatically simplifying application development. The framework enables developers to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build chatbots and conversational AI&lt;/li&gt;
&lt;li&gt;Create autonomous agents&lt;/li&gt;
&lt;li&gt;Implement Retrieval-Augmented Generation (RAG) workflows&lt;/li&gt;
&lt;li&gt;Manage prompt templates and chains&lt;/li&gt;
&lt;li&gt;Maintain conversation memory&lt;/li&gt;
&lt;li&gt;Integrate with vector databases and external APIs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Language Support:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;LangChain primarily supports Python but also has libraries for JavaScript, TypeScript, and Java (through LangChain4j).&lt;/p&gt;
&lt;h3 id=&quot;oci-generative-ai-integration-with-langchain&quot;&gt;OCI Generative AI Integration with LangChain&lt;/h3&gt;
&lt;p&gt;Oracle Cloud Infrastructure Generative AI has an official integration with LangChain, providing native support through wrapper classes that make OCI's LLMs and embedding models easily accessible within LangChain applications.&lt;/p&gt;
&lt;h4 id=&quot;the-official-langchain-oci-package&quot;&gt;The Official langchain-oci Package&lt;/h4&gt;
&lt;p&gt;As of 2025, Oracle maintains the official &lt;code&gt;langchain-oci&lt;/code&gt; package that replaces the earlier community integrations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important Migration Note:&lt;/strong&gt; The OCI integrations available in langchain-community are now deprecated. All future development, bug fixes, and feature enhancements are hosted in the new langchain-oci package.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Installation:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pip install langchain-oci
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This package provides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ChatOCIGenAI&lt;/strong&gt;: Chat models from OCI Generative AI&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OCIGenAI&lt;/strong&gt;: Text generation from OCI Generative AI  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OCIGenAIEmbeddings&lt;/strong&gt;: Embedding models from OCI Generative AI&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ChatOCIModelDeployment&lt;/strong&gt;: Integration with OCI Data Science model endpoints&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Oracle AI Vector Search&lt;/strong&gt;: Native vector store integration&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;available-model-classes&quot;&gt;Available Model Classes&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;1. ChatOCIGenAI - Conversational AI&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The primary class for building chat applications with OCI Generative AI models.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from langchain_oci import ChatOCIGenAI

llm = ChatOCIGenAI(
    model_id=&quot;meta.llama-4-maverick-17b-128e-instruct-fp8&quot;,
    service_endpoint=&quot;https://inference.generativeai.us-chicago-1.oci.oraclecloud.com&quot;,
    compartment_id=&quot;MY_COMPARTMENT_ID&quot;,
    model_kwargs={&quot;temperature&quot;: 0, &quot;max_tokens&quot;: 500},
    auth_profile=&quot;MY_AUTH_PROFILE&quot;,
    is_stream=True
)

response = llm.invoke(&quot;Sing a ballad of LangChain.&quot;)
print(response.content)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Supported Features:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Multi-turn conversations with context retention&lt;/li&gt;
&lt;li&gt;Streaming responses for real-time output&lt;/li&gt;
&lt;li&gt;Structured output generation&lt;/li&gt;
&lt;li&gt;Tool calling and function execution&lt;/li&gt;
&lt;li&gt;Parallel tool calling (Llama 4+ models only)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2. OCIGenAI - Text Generation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For simpler text generation tasks without conversational context.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from langchain_oci import OCIGenAI

llm = OCIGenAI()
response = llm.invoke(&quot;The meaning of life is&quot;)
print(response)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3. OCIGenAIEmbeddings - Vector Representations&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Convert text into semantic embeddings for similarity search and RAG applications.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from langchain_oci import OCIGenAIEmbeddings

embeddings = OCIGenAIEmbeddings(
    model_id=&quot;cohere.embed-v4.0&quot;,
    service_endpoint=&quot;https://inference.generativeai.us-chicago-1.oci.oraclecloud.com&quot;,
    compartment_id=&quot;compartment_id&quot;
)

# Single query embedding
query = &quot;This is a query in English.&quot;
response = embeddings.embed_query(query)

# Multiple document embeddings
documents = [&quot;This is a sample document&quot;, &quot;and here is another one&quot;]
response = embeddings.embed_documents(documents)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Authentication Methods:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;LangChain OCI integration supports standard SDK authentication:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;API Key (default)&lt;/li&gt;
&lt;li&gt;Security Token&lt;/li&gt;
&lt;li&gt;Instance Principal&lt;/li&gt;
&lt;li&gt;Resource Principal&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;advanced-features&quot;&gt;Advanced Features&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Structured Output:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ChatOCIGenAI supports structured output generation using function calling, JSON schema, or JSON mode.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from langchain_oci import ChatOCIGenAI

llm = ChatOCIGenAI(
    model_id=&quot;meta.llama-4-maverick-17b-128e-instruct-fp8&quot;,
    service_endpoint=&quot;https://inference.generativeai.us-chicago-1.oci.oraclecloud.com&quot;,
    compartment_id=&quot;MY_COMPARTMENT_ID&quot;
)

# Define your structured output schema
structured_llm = llm.with_structured_output(YourSchema)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Parallel Tool Calling:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Llama 4+ models support parallel tool calling, allowing multiple tools to execute simultaneously.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;llm_with_tools = llm.bind_tools(
    [get_weather, calculate_tip, get_population],
    parallel_tool_calls=True  # Tools can execute simultaneously
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: Llama 3.x (including 3.3) and Cohere models will raise an error if parallel tool calling is used.&lt;/p&gt;
&lt;h3 id=&quot;langchain-prompt-templates&quot;&gt;LangChain Prompt Templates&lt;/h3&gt;
&lt;p&gt;LangChain prompts can be created using two types of prompt templates, each optimized for different use cases.&lt;/p&gt;
&lt;h4 id=&quot;1-string-prompt-template&quot;&gt;1. String Prompt Template&lt;/h4&gt;
&lt;p&gt;Outputs a simple string, ideal for basic text generation tasks.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from langchain_core.prompts import PromptTemplate

template = &quot;&quot;&quot;
You are a helpful assistant. Translate the following text to French:
{text}
&quot;&quot;&quot;

prompt = PromptTemplate.from_template(template)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;2-chat-prompt-template&quot;&gt;2. Chat Prompt Template&lt;/h4&gt;
&lt;p&gt;Supports a list of messages with different roles (system, user, assistant), perfect for conversational AI.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from langchain_core.prompts import ChatPromptTemplate

template = ChatPromptTemplate.from_messages([
    (&quot;system&quot;, &quot;You are a helpful assistant specialized in {domain}.&quot;),
    (&quot;user&quot;, &quot;{question}&quot;)
])

prompt = template.invoke({
    &quot;domain&quot;: &quot;Italian cuisine&quot;,
    &quot;question&quot;: &quot;What are the best ingredients for carbonara?&quot;
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Message Types:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;System messages&lt;/strong&gt;: Set behavior and context&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User messages&lt;/strong&gt;: User queries and inputs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Assistant messages&lt;/strong&gt;: Previous AI responses (for context)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Function messages&lt;/strong&gt;: Tool/function call results&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;creating-chains-with-lcel&quot;&gt;Creating Chains with LCEL&lt;/h3&gt;
&lt;p&gt;LangChain Expression Language (LCEL) enables declarative chain creation, offering a more concise and composable approach than traditional Python classes.&lt;/p&gt;
&lt;h4 id=&quot;declarative-chains-with-lcel&quot;&gt;Declarative Chains with LCEL&lt;/h4&gt;
&lt;p&gt;LCEL uses the pipe operator (&lt;code&gt;|&lt;/code&gt;) to chain components together.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_oci import ChatOCIGenAI

# Define components
prompt = ChatPromptTemplate.from_template(
    &quot;If the text is a question, first translate the question and then &quot;
    &quot;answer the question in French.: {text}&quot;
)

llm = ChatOCIGenAI(
    model_id=&quot;meta.llama-4-scout-17b-16e-instruct&quot;,
    service_endpoint=&quot;https://inference.generativeai.us-chicago-1.oci.oraclecloud.com&quot;,
    compartment_id=&quot;&amp;lt;sandbox-compartment&amp;gt;&quot;,
    model_kwargs={&quot;temperature&quot;: 0, &quot;max_tokens&quot;: 500}
)

output_parser = StrOutputParser()

# Create chain using LCEL
chain = prompt | llm | output_parser

# Execute chain
result = chain.invoke({&quot;text&quot;: &quot;What are the four seasons in a year?&quot;})
print(result)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;La traduction de la question est : Quelles sont les quatre saisons dans une année?
Les quatre saisons dans une année sont : le printemps, l'été, l'automne et l'hiver.
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;traditional-python-classes&quot;&gt;Traditional Python Classes&lt;/h4&gt;
&lt;p&gt;Alternatively, use Python classes like &lt;code&gt;LLMChain&lt;/code&gt; for explicit chain construction.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from langchain.chains import LLMChain
from langchain_core.prompts import PromptTemplate
from langchain_oci import ChatOCIGenAI

llm = ChatOCIGenAI(model_id=&quot;meta.llama-4-scout-17b-16e-instruct&quot;, ...)
prompt = PromptTemplate.from_template(&quot;Translate to French: {text}&quot;)

chain = LLMChain(llm=llm, prompt=prompt)
result = chain.run(text=&quot;Hello, world!&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;LCEL vs Python Classes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LCEL&lt;/strong&gt;: More concise, composable, modern approach (recommended)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Python Classes&lt;/strong&gt;: More explicit, traditional, verbose&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;langchain-memory-maintaining-conversation-context&quot;&gt;LangChain Memory: Maintaining Conversation Context&lt;/h3&gt;
&lt;p&gt;LangChain memory provides the ability to store information about past interactions, crucial for building conversational applications.&lt;/p&gt;
&lt;h4 id=&quot;memory-types&quot;&gt;Memory Types&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Conversation Buffer Memory:&lt;/strong&gt;&lt;br&gt;
Stores the entire conversation history.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from langchain.memory import ConversationBufferMemory

memory = ConversationBufferMemory()
memory.save_context({&quot;input&quot;: &quot;Hi&quot;}, {&quot;output&quot;: &quot;Hello! How can I help?&quot;})
memory.save_context({&quot;input&quot;: &quot;What's the weather?&quot;}, {&quot;output&quot;: &quot;It's sunny!&quot;})

print(memory.load_memory_variables({}))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Conversation Buffer Window Memory:&lt;/strong&gt;&lt;br&gt;
Maintains only the last K interactions to manage token limits.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from langchain.memory import ConversationBufferWindowMemory

memory = ConversationBufferWindowMemory(k=2)  # Keep last 2 exchanges
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Conversation Summary Memory:&lt;/strong&gt;&lt;br&gt;
Uses an LLM to summarize conversation history, maintaining context while reducing tokens.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from langchain.memory import ConversationSummaryMemory

memory = ConversationSummaryMemory(llm=llm)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;oracle-database-23ai-as-a-vector-store&quot;&gt;Oracle Database 23ai as a Vector Store&lt;/h3&gt;
&lt;p&gt;Oracle Database 23ai can be used as a powerful vector store to generate and manage embeddings, seamlessly integrating with LangChain for RAG applications.&lt;/p&gt;
&lt;h4 id=&quot;why-oracle-database-23ai-for-vector-storage-&quot;&gt;Why Oracle Database 23ai for Vector Storage?&lt;/h4&gt;
&lt;p&gt;Oracle Database 23ai supports native AI Vector Search, enabling:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Semantic similarity search&lt;/strong&gt; on text, documents, images, and unstructured data&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Combined relational and vector queries&lt;/strong&gt; in a single system&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pre-filtering, in-filtering, and post-filtering&lt;/strong&gt; for enhanced search capabilities&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multiple distance metrics&lt;/strong&gt;: Cosine, Euclidean, dot product&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HNSW indexing&lt;/strong&gt; for high-performance similarity search&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integration with existing enterprise data&lt;/strong&gt; without data duplication&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;langchain-oracle-vector-store-integration&quot;&gt;LangChain Oracle Vector Store Integration&lt;/h4&gt;
&lt;p&gt;Oracle AI Vector Search integrates with LangChain at various levels, providing document loaders, text splitters, embeddings, and vector stores.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Installation:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pip install langchain-oracle
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Basic Vector Store Usage:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from langchain_community.vectorstores import OracleVS
from langchain_oracle.embeddings import OCIGenAIEmbeddings
from langchain.schema import Document
import oracledb

# Connect to Oracle Database 23ai
conn = oracledb.connect(
    user=&quot;username&quot;,
    password=&quot;password&quot;,
    dsn=&quot;localhost/FREEPDB1&quot;
)

# Create embedding model
embeddings = OCIGenAIEmbeddings(
    model_id=&quot;cohere.embed-v4.0&quot;,
    service_endpoint=&quot;https://inference.generativeai.us-chicago-1.oci.oraclecloud.com&quot;,
    compartment_id=&quot;compartment_id&quot;
)

# Prepare documents
documents = [
    Document(
        page_content=&quot;LangChain is a framework for LLM applications&quot;,
        metadata={&quot;id&quot;: &quot;doc1&quot;, &quot;source&quot;: &quot;documentation&quot;}
    ),
    Document(
        page_content=&quot;Oracle Database 23ai supports vector search natively&quot;,
        metadata={&quot;id&quot;: &quot;doc2&quot;, &quot;source&quot;: &quot;announcement&quot;}
    )
]

# Create vector store
vector_store = OracleVS.from_documents(
    documents,
    embeddings,
    client=conn,
    table_name=&quot;LANGCHAIN_VECTORS&quot;,
    distance_strategy=DistanceStrategy.COSINE
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;creating-hnsw-index-for-performance&quot;&gt;Creating HNSW Index for Performance&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import oraclevs

oraclevs.create_index(
    conn,
    vector_store,
    params={
        &quot;idx_name&quot;: &quot;hnsw_idx1&quot;,
        &quot;idx_type&quot;: &quot;HNSW&quot;,
        &quot;accuracy&quot;: 97,  # Target accuracy percentage
        &quot;parallel&quot;: 8     # Number of parallel workers
    }
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;similarity-search&quot;&gt;Similarity Search&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Perform similarity search
query = &quot;What is LangChain?&quot;
results = vector_store.similarity_search(query, k=3)

for doc in results:
    print(f&quot;Content: {doc.page_content}&quot;)
    print(f&quot;Metadata: {doc.metadata}\n&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;accessing-oci-generative-ai-from-oracle-database&quot;&gt;Accessing OCI Generative AI from Oracle Database&lt;/h3&gt;
&lt;p&gt;Oracle Database 23ai can directly access OCI Generative AI services through built-in APIs and Select AI capabilities.&lt;/p&gt;
&lt;h4 id=&quot;using-dbms-cloud-for-rest-api-access&quot;&gt;Using DBMS_CLOUD for REST API Access&lt;/h4&gt;
&lt;p&gt;You can access OCI Generative AI service using the &lt;code&gt;DBMS_CLOUD&lt;/code&gt; REST API directly from SQL.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- Create credential for OCI authentication
BEGIN
  DBMS_CLOUD.CREATE_CREDENTIAL(
    credential_name =&amp;gt; 'OCI_CRED',
    username =&amp;gt; 'ocid1.user.oc1...',
    password =&amp;gt; '&amp;lt;your-auth-token&amp;gt;'
  );
END;
/

-- Call OCI Generative AI endpoint
DECLARE
  l_response CLOB;
BEGIN
  l_response := DBMS_CLOUD.SEND_REQUEST(
    credential_name =&amp;gt; 'OCI_CRED',
    uri =&amp;gt; 'https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/...',
    method =&amp;gt; 'POST',
    body =&amp;gt; '{
      &quot;model&quot;: &quot;cohere.command-r-plus&quot;,
      &quot;prompt&quot;: &quot;Explain quantum computing&quot;,
      &quot;max_tokens&quot;: 500
    }'
  );
  
  DBMS_OUTPUT.PUT_LINE(l_response);
END;
/
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;select-ai-natural-language-to-sql&quot;&gt;Select AI: Natural Language to SQL&lt;/h3&gt;
&lt;p&gt;Select AI enables SQL access to generative AI using Large Language Models (LLMs) and embedding models, including support for natural language to SQL query generation and retrieval-augmented generation.&lt;/p&gt;
&lt;h4 id=&quot;how-select-ai-works&quot;&gt;How Select AI Works&lt;/h4&gt;
&lt;p&gt;Select AI translates natural language questions into SQL queries that the database understands, then uses LLMs trained to infer user intent to interpret queries and return desired answers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Capabilities:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Select AI automatically builds and maintains a vector index using metadata for applicable objects in your schema, using semantic similarity search to choose the most relevant objects based on user prompts.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Natural language to SQL (NL2SQL / text-to-SQL)&lt;/strong&gt; query generation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automatic metadata augmentation&lt;/strong&gt; with table/column comments, constraints, annotations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Semantic similarity search&lt;/strong&gt; to select relevant schema objects&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RAG support&lt;/strong&gt; for context-augmented responses&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-dialect support&lt;/strong&gt; including Oracle SQL and SQLite&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;setting-up-select-ai&quot;&gt;Setting Up Select AI&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- Create credential for LLM provider
BEGIN
  DBMS_CLOUD.CREATE_CREDENTIAL(
    credential_name =&amp;gt; 'COHERE_CRED',
    username =&amp;gt; 'COHERE',
    password =&amp;gt; '&amp;lt;your-api-key&amp;gt;'
  );
END;
/

-- Create AI profile
BEGIN
  DBMS_CLOUD_AI.CREATE_PROFILE(
    profile_name =&amp;gt; 'COHERE',
    attributes =&amp;gt; '{
      &quot;provider&quot;: &quot;cohere&quot;,
      &quot;credential_name&quot;: &quot;COHERE_CRED&quot;,
      &quot;model&quot;: &quot;cohere.command-a-03-2025&quot;,
      &quot;object_list&quot;: [{&quot;owner&quot;: &quot;ADB_USER&quot;}],
      &quot;max_tokens&quot;: 512,
      &quot;temperature&quot;: 0.5,
      &quot;comments&quot;: true,
      &quot;constraints&quot;: true
    }'
  );
END;
/
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;using-select-ai&quot;&gt;Using Select AI&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Run SQL from Natural Language:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT AI What are the top 5 products by revenue this quarter?;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Show Generated SQL:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT AI showsql What are the top 5 products by revenue this quarter?;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Explain SQL in Natural Language:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT AI explainsql SELECT * FROM sales WHERE region = 'West';
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Chat Mode:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT AI chat Who won the 2024 World Series?;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;select-ai-with-rag&quot;&gt;Select AI with RAG&lt;/h4&gt;
&lt;p&gt;Select AI supports RAG using Oracle AI Vector Search, integrating vector database content to deliver more accurate results from LLMs through semantic similarity search.&lt;/p&gt;
&lt;p&gt;Select AI RAG automates the orchestration steps of transforming prompts into vectors and performing semantic similarity search on vector database content, making it easy to use LLMs with your private data using natural language prompts.&lt;/p&gt;
&lt;h3 id=&quot;complete-rag-application-example&quot;&gt;Complete RAG Application Example&lt;/h3&gt;
&lt;p&gt;Here's a complete example combining OCI Generative AI, LangChain, and Oracle Database 23ai:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from langchain_oci import ChatOCIGenAI, OCIGenAIEmbeddings
from langchain_community.vectorstores import OracleVS
from langchain_core.prompts import ChatPromptTemplate
from langchain.schema import Document
from langchain_core.output_parsers import StrOutputParser
import oracledb

# 1. Connect to Oracle Database 23ai
conn = oracledb.connect(
    user=&quot;username&quot;,
    password=&quot;password&quot;,
    dsn=&quot;localhost/FREEPDB1&quot;
)

# 2. Initialize embedding model
embeddings = OCIGenAIEmbeddings(
    model_id=&quot;cohere.embed-v4.0&quot;,
    service_endpoint=&quot;https://inference.generativeai.us-chicago-1.oci.oraclecloud.com&quot;,
    compartment_id=&quot;compartment_id&quot;
)

# 3. Load documents into vector store
documents = [
    Document(page_content=&quot;Your document content here&quot;, metadata={&quot;source&quot;: &quot;doc1&quot;}),
    # ... more documents
]

vector_store = OracleVS.from_documents(
    documents,
    embeddings,
    client=conn,
    table_name=&quot;KNOWLEDGE_BASE&quot;
)

# 4. Initialize LLM
llm = ChatOCIGenAI(
    model_id=&quot;meta.llama-4-scout-17b-16e-instruct&quot;,
    service_endpoint=&quot;https://inference.generativeai.us-chicago-1.oci.oraclecloud.com&quot;,
    compartment_id=&quot;compartment_id&quot;,
    model_kwargs={&quot;temperature&quot;: 0.3, &quot;max_tokens&quot;: 1000}
)

# 5. Create RAG chain
template = &quot;&quot;&quot;
Answer the question based on the following context:

Context: {context}

Question: {question}

Answer:
&quot;&quot;&quot;

prompt = ChatPromptTemplate.from_template(template)

# 6. Query function
def ask_question(question: str):
    # Retrieve relevant documents
    docs = vector_store.similarity_search(question, k=3)
    context = &quot;\n\n&quot;.join([doc.page_content for doc in docs])
    
    # Create and execute chain
    chain = prompt | llm | StrOutputParser()
    response = chain.invoke({&quot;context&quot;: context, &quot;question&quot;: question})
    
    return response

# 7. Use the RAG system
answer = ask_question(&quot;What are the benefits of Oracle Database 23ai?&quot;)
print(answer)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;best-practices-for-oci-langchain-applications&quot;&gt;Best Practices for OCI + LangChain Applications&lt;/h3&gt;
&lt;h4 id=&quot;1-choose-the-right-components&quot;&gt;1. Choose the Right Components&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ChatOCIGenAI&lt;/strong&gt; for conversational applications&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OCIGenAI&lt;/strong&gt; for simple text generation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OCIGenAIEmbeddings&lt;/strong&gt; for semantic search and RAG&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Oracle Database 23ai&lt;/strong&gt; as vector store for enterprise data&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;2-optimize-embedding-storage&quot;&gt;2. Optimize Embedding Storage&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Use appropriate distance metrics (cosine for text similarity)&lt;/li&gt;
&lt;li&gt;Create HNSW indexes for large datasets&lt;/li&gt;
&lt;li&gt;Leverage metadata filtering for refined searches&lt;/li&gt;
&lt;li&gt;Batch document processing for efficiency&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;3-manage-memory-effectively&quot;&gt;3. Manage Memory Effectively&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Use ConversationBufferWindowMemory for long conversations&lt;/li&gt;
&lt;li&gt;Implement ConversationSummaryMemory for token efficiency&lt;/li&gt;
&lt;li&gt;Clear memory when starting new conversation threads&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;4-leverage-lcel-for-composability&quot;&gt;4. Leverage LCEL for Composability&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Build modular, reusable chains&lt;/li&gt;
&lt;li&gt;Combine multiple chains for complex workflows&lt;/li&gt;
&lt;li&gt;Use parallel execution where appropriate&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;5-implement-proper-error-handling&quot;&gt;5. Implement Proper Error Handling&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;try:
    response = chain.invoke(input_data)
except Exception as e:
    logging.error(f&quot;Chain execution failed: {e}&quot;)
    # Implement fallback behavior
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;6-monitor-and-optimize-costs&quot;&gt;6. Monitor and Optimize Costs&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Cache frequently accessed embeddings&lt;/li&gt;
&lt;li&gt;Use appropriate model sizes (Scout vs Maverick)&lt;/li&gt;
&lt;li&gt;Implement rate limiting for user requests&lt;/li&gt;
&lt;li&gt;Monitor token usage across applications&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The integration of OCI Generative AI with LangChain provides a powerful, enterprise-ready platform for building AI applications. Key takeaways:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Official Integration:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;langchain-oci package provides native support for OCI Generative AI&lt;/li&gt;
&lt;li&gt;Supports chat models, text generation, and embeddings&lt;/li&gt;
&lt;li&gt;Compatible with OCI Data Science model deployments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Prompt Engineering:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;String and Chat prompt templates for different use cases&lt;/li&gt;
&lt;li&gt;LCEL for declarative chain creation&lt;/li&gt;
&lt;li&gt;Memory management for conversational context&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Oracle Database 23ai:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Native vector store with LangChain integration&lt;/li&gt;
&lt;li&gt;Combines relational and vector search in one system&lt;/li&gt;
&lt;li&gt;Select AI for natural language to SQL generation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Complete AI Stack:&lt;/strong&gt;&lt;br&gt;
By combining OCI Generative AI (LLMs + embeddings), LangChain (orchestration), and Oracle Database 23ai (vector store + Select AI), you can build sophisticated RAG applications, conversational agents, and enterprise AI solutions with security, scalability, and performance.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/10026/oci-generative-ai-and-langchain-building-enterprise-ai-applications-with-oracle</guid>
<pubDate>Mon, 19 Jan 2026 17:14:03 +0000</pubDate>
</item>
<item>
<title>LangChain vs LangGraph vs LangSmith: Understanding the Ecosystem</title>
<link>https://coderlegion.com/9900/langchain-vs-langgraph-vs-langsmith-understanding-the-ecosystem</link>
<description>&lt;blockquote&gt;&lt;p&gt;Building LLM apps isn’t just about prompts anymore.&lt;br&gt;
It’s about &lt;strong&gt;composition&lt;/strong&gt;, &lt;strong&gt;orchestration&lt;/strong&gt;, and &lt;strong&gt;observability&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;tl-dr&quot;&gt;TL;DR&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LangChain&lt;/strong&gt; provides the foundational building blocks for creating LLM applications through modular components and a unified interface for working with different AI providers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LangGraph&lt;/strong&gt; extends this foundation with &lt;strong&gt;stateful, graph-based orchestration&lt;/strong&gt; for complex multi-agent workflows requiring loops, branching, and persistent state.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LangSmith&lt;/strong&gt; completes the picture by offering &lt;strong&gt;observability, tracing, and evaluation&lt;/strong&gt; tools for debugging and monitoring LLM applications in production.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Use:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LangChain&lt;/strong&gt; for straightforward chains and RAG systems&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LangGraph&lt;/strong&gt; when you need sophisticated state management and agent coordination&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LangSmith&lt;/strong&gt; throughout development and production for visibility into behavior&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;hands-on-github-repositories&quot;&gt;Hands-on GitHub Repositories&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LangChain RAG Project&lt;/strong&gt; → &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/rajkundalia/langchain-rag-project&quot;&gt;https://github.com/rajkundalia/langchain-rag-project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LangGraph Analyzer&lt;/strong&gt; → &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/rajkundalia/langgraph-analyzer&quot;&gt;https://github.com/rajkundalia/langgraph-analyzer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LangSmith Learning&lt;/strong&gt; → &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/rajkundalia/langsmith-learning&quot;&gt;https://github.com/rajkundalia/langsmith-learning&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;introduction-2&quot;&gt;Introduction&lt;/h3&gt;
&lt;p&gt;The landscape of LLM application development has evolved rapidly since 2022.&lt;/p&gt;
&lt;p&gt;What began as simple prompt–response interactions has grown into &lt;strong&gt;multi-step workflows&lt;/strong&gt; involving retrieval systems, tool usage, autonomous agents, and long-running processes. This evolution introduced &lt;strong&gt;new problems at each stage&lt;/strong&gt; of the development lifecycle.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The composition problem&lt;/strong&gt; → How do you connect prompts, models, tools, and data?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The orchestration problem&lt;/strong&gt; → How do you manage branching, retries, loops, and shared state?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The observability problem&lt;/strong&gt; → How do you debug, evaluate, and monitor these systems?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The LangChain ecosystem emerged to address each layer:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Problem       &lt;/th&gt;&lt;th&gt;Tool      &lt;/th&gt;&lt;th&gt;Year&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Composition   &lt;/td&gt;&lt;td&gt;LangChain &lt;/td&gt;&lt;td&gt;2022&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Orchestration &lt;/td&gt;&lt;td&gt;LangGraph &lt;/td&gt;&lt;td&gt;2024&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Observability &lt;/td&gt;&lt;td&gt;LangSmith &lt;/td&gt;&lt;td&gt;2023–2024&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Each tool targets a &lt;strong&gt;specific layer&lt;/strong&gt; in the LLM application stack.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;langchain-the-foundation&quot;&gt;LangChain: The Foundation&lt;/h3&gt;
&lt;p&gt;LangChain is the &lt;strong&gt;core framework&lt;/strong&gt; for building LLM-powered applications.&lt;/p&gt;
&lt;p&gt;Its primary goal is abstraction: different LLM providers expose different APIs, capabilities, and quirks. LangChain hides these differences behind a &lt;strong&gt;unified interface&lt;/strong&gt;.&lt;/p&gt;
&lt;h4 id=&quot;core-building-blocks&quot;&gt;Core Building Blocks&lt;/h4&gt;
&lt;p&gt;LangChain is composed of modular, swappable components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prompts&lt;/strong&gt; – Templates and structured inputs for models&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Models&lt;/strong&gt; – OpenAI, Anthropic, Google, or local LLMs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory&lt;/strong&gt; – Conversation history and contextual state&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tools&lt;/strong&gt; – Function calls to external systems&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Retrievers&lt;/strong&gt; – Vector databases and RAG pipelines&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;lcel-langchain-expression-language&quot;&gt;LCEL: LangChain Expression Language&lt;/h4&gt;
&lt;p&gt;What ties everything together is &lt;strong&gt;LCEL&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;LCEL introduces a &lt;strong&gt;declarative, pipe-based syntax&lt;/strong&gt; for composing chains:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;prompt | model | output_parser
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of writing imperative glue code, you describe &lt;strong&gt;data flow&lt;/strong&gt;.&lt;/p&gt;
&lt;h4 id=&quot;why-lcel-matters&quot;&gt;Why LCEL Matters&lt;/h4&gt;
&lt;p&gt;LCEL enables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Automatic async, streaming, and batch execution&lt;/li&gt;
&lt;li&gt;Built-in LangSmith tracing&lt;/li&gt;
&lt;li&gt;Parallel execution of independent steps&lt;/li&gt;
&lt;li&gt;A unified &lt;code&gt;Runnable&lt;/code&gt; interface (&lt;code&gt;invoke&lt;/code&gt;, &lt;code&gt;batch&lt;/code&gt;, &lt;code&gt;stream&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This makes chains &lt;strong&gt;faster&lt;/strong&gt;, &lt;strong&gt;cleaner&lt;/strong&gt;, and easier to reason about.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;multi-provider-support&quot;&gt;Multi-Provider Support&lt;/h4&gt;
&lt;p&gt;LangChain supports dozens of LLM providers and integrations.&lt;/p&gt;
&lt;p&gt;You can switch providers by changing &lt;strong&gt;one line of configuration&lt;/strong&gt;, enabling:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vendor independence&lt;/li&gt;
&lt;li&gt;A/B testing across models&lt;/li&gt;
&lt;li&gt;Cost and latency optimization&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;when-langchain-is-enough&quot;&gt;When LangChain Is Enough&lt;/h4&gt;
&lt;p&gt;Use LangChain when your workflow is primarily:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Input → Process → Output
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Typical use cases include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chatbots with memory&lt;/li&gt;
&lt;li&gt;RAG-based Q&amp;amp;A systems&lt;/li&gt;
&lt;li&gt;Natural language → SQL generation&lt;/li&gt;
&lt;li&gt;Linear tool pipelines&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your application doesn’t need complex branching or shared long-lived state, &lt;strong&gt;LangChain is the right tool&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;section&quot;&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7a2mw7h25kemz76pn20y.png&quot; alt=&quot;LangChain Component Flow&quot;&gt;&lt;/h3&gt;
&lt;h3 id=&quot;langgraph-stateful-agent-orchestration&quot;&gt;LangGraph: Stateful Agent Orchestration&lt;/h3&gt;
&lt;p&gt;LangGraph solves the &lt;strong&gt;orchestration problem&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;As soon as your application needs to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;make decisions,&lt;/li&gt;
&lt;li&gt;loop,&lt;/li&gt;
&lt;li&gt;retry,&lt;/li&gt;
&lt;li&gt;or coordinate multiple agents, linear chains start to break down.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;graph-based-architecture&quot;&gt;Graph-Based Architecture&lt;/h4&gt;
&lt;p&gt;LangGraph models your application as a &lt;strong&gt;directed graph&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Nodes&lt;/strong&gt; → processing steps or agents&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Edges&lt;/strong&gt; → execution flow between nodes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This enables patterns that are hard or impossible with chains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Loops and retries&lt;/li&gt;
&lt;li&gt;Conditional branching&lt;/li&gt;
&lt;li&gt;Parallel execution&lt;/li&gt;
&lt;li&gt;Shared, persistent state&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;state-as-a-first-class-concept&quot;&gt;State as a First-Class Concept&lt;/h4&gt;
&lt;p&gt;Every LangGraph workflow operates on a &lt;strong&gt;shared state object&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nodes receive the current state&lt;/li&gt;
&lt;li&gt;They compute updates&lt;/li&gt;
&lt;li&gt;Updates are merged back into state&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This allows multiple agents to collaborate naturally.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Research agent gathers sources&lt;/li&gt;
&lt;li&gt;Fact-checking agent validates claims&lt;/li&gt;
&lt;li&gt;Synthesis agent produces the final answer&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All without complex message passing.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;conditional-routing&quot;&gt;Conditional Routing&lt;/h4&gt;
&lt;p&gt;LangGraph supports &lt;strong&gt;conditional edges&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;A function decides which node runs next based on runtime state:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Route customer queries to specialist agents&lt;/li&gt;
&lt;li&gt;Loop back when required information is missing&lt;/li&gt;
&lt;li&gt;Retry until success conditions are met&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;persistence-amp-checkpointing&quot;&gt;Persistence &amp;amp; Checkpointing&lt;/h4&gt;
&lt;p&gt;LangGraph includes built-in &lt;strong&gt;checkpointing&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Persist state across restarts&lt;/li&gt;
&lt;li&gt;Resume long-running workflows&lt;/li&gt;
&lt;li&gt;Support human-in-the-loop pauses&lt;/li&gt;
&lt;li&gt;Enable time-travel debugging&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is critical for production-grade agent systems.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;visualization-support&quot;&gt;Visualization Support&lt;/h4&gt;
&lt;p&gt;LangGraph workflows are inspectable and exportable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mermaid diagrams for documentation&lt;/li&gt;
&lt;li&gt;PNG images for presentations&lt;/li&gt;
&lt;li&gt;ASCII graphs for terminal debugging&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This makes complex agent systems &lt;strong&gt;understandable and communicable&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;when-you-need-langgraph&quot;&gt;When You Need LangGraph&lt;/h4&gt;
&lt;p&gt;Choose LangGraph when you need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Explicit shared state&lt;/li&gt;
&lt;li&gt;Runtime decision-making&lt;/li&gt;
&lt;li&gt;Retry and failure recovery&lt;/li&gt;
&lt;li&gt;Multi-agent coordination&lt;/li&gt;
&lt;li&gt;Long-running workflows&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A classic example is an &lt;strong&gt;autonomous research agent&lt;/strong&gt; that iteratively searches, reads, verifies, and synthesizes information.&lt;/p&gt;
&lt;h3 id=&quot;section-1&quot;&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e6w9w6egyyj8r4c3ricl.png&quot; alt=&quot;LangGraph State Machine Example&quot;&gt;&lt;/h3&gt;
&lt;h3 id=&quot;langsmith-the-observability-layer&quot;&gt;LangSmith: The Observability Layer&lt;/h3&gt;
&lt;p&gt;LangSmith answers the question:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;“What is my LLM application actually doing?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It doesn’t build workflows — it &lt;strong&gt;illuminates them&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;tracing-everything&quot;&gt;Tracing Everything&lt;/h4&gt;
&lt;p&gt;LangSmith captures full execution traces:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prompts and responses&lt;/li&gt;
&lt;li&gt;Token usage and latency&lt;/li&gt;
&lt;li&gt;Component call stacks&lt;/li&gt;
&lt;li&gt;Errors and retries&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can drill down from:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a full workflow run&lt;br&gt;
→ to a single LLM call.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This makes debugging &lt;em&gt;dramatically&lt;/em&gt; easier.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;evaluation-amp-regression-testing&quot;&gt;Evaluation &amp;amp; Regression Testing&lt;/h4&gt;
&lt;p&gt;LangSmith allows you to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create evaluation datasets&lt;/li&gt;
&lt;li&gt;Run structured tests&lt;/li&gt;
&lt;li&gt;Track quality metrics&lt;/li&gt;
&lt;li&gt;Compare prompts and models&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This enables &lt;strong&gt;regression testing&lt;/strong&gt; for LLM apps — a must-have for production systems.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;production-monitoring&quot;&gt;Production Monitoring&lt;/h4&gt;
&lt;p&gt;In production, LangSmith tracks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Response times&lt;/li&gt;
&lt;li&gt;Error rates&lt;/li&gt;
&lt;li&gt;Token and cost trends&lt;/li&gt;
&lt;li&gt;Usage by workflow or user&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Alerts help you catch issues early and optimize costs.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;framework-agnostic&quot;&gt;Framework-Agnostic&lt;/h4&gt;
&lt;p&gt;While LangSmith integrates seamlessly with LangChain and LangGraph, it’s &lt;strong&gt;not limited to them&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You can instrument &lt;em&gt;any&lt;/em&gt; LLM application with LangSmith.&lt;/p&gt;
&lt;h3 id=&quot;section-2&quot;&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dx2l37b7n29anhmsrrhh.png&quot; alt=&quot;LangSmith Diagram&quot;&gt;&lt;/h3&gt;
&lt;h3 id=&quot;quick-comparison&quot;&gt;Quick Comparison&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Tool      &lt;/th&gt;&lt;th&gt;Solves        &lt;/th&gt;&lt;th&gt;Use When&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;LangChain &lt;/td&gt;&lt;td&gt;Composition   &lt;/td&gt;&lt;td&gt;Linear workflows, RAG, simple agents&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;LangGraph &lt;/td&gt;&lt;td&gt;Orchestration &lt;/td&gt;&lt;td&gt;Branching, loops, shared state, multi-agent&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;LangSmith &lt;/td&gt;&lt;td&gt;Observability &lt;/td&gt;&lt;td&gt;Debugging, evaluation, production monitoring&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;section-3&quot;&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yia3pj7oyxnurc75suxn.png&quot; alt=&quot;Decision Tree: Which Tool to Use?&quot;&gt;&lt;/h3&gt;
&lt;h3 id=&quot;the-broader-ecosystem&quot;&gt;The Broader Ecosystem&lt;/h3&gt;
&lt;h4 id=&quot;langflow&quot;&gt;LangFlow&lt;/h4&gt;
&lt;p&gt;LangFlow provides a &lt;strong&gt;visual, drag-and-drop&lt;/strong&gt; interface for building LangChain workflows.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Great for prototyping&lt;/li&gt;
&lt;li&gt;Helpful for non-technical collaboration&lt;/li&gt;
&lt;li&gt;Often exported to code for production&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;model-context-protocol-mcp-&quot;&gt;Model Context Protocol (MCP)&lt;/h4&gt;
&lt;p&gt;MCP (by Anthropic) standardizes &lt;strong&gt;tool and resource access&lt;/strong&gt; for LLMs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Works at the tool/retriever layer&lt;/li&gt;
&lt;li&gt;Complements LangChain and LangGraph&lt;/li&gt;
&lt;li&gt;Reduces custom integration effort&lt;/li&gt;
&lt;li&gt;Framework-agnostic&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;MCP does &lt;strong&gt;not&lt;/strong&gt; replace orchestration tools — it enhances connectivity.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;conclusion-2&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;The LangChain ecosystem is &lt;strong&gt;layered, not competitive&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LangChain&lt;/strong&gt; builds the core logic&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LangGraph&lt;/strong&gt; manages complex workflows&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LangSmith&lt;/strong&gt; makes everything observable&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most serious LLM applications will use &lt;strong&gt;more than one&lt;/strong&gt; of these tools.&lt;/p&gt;
&lt;p&gt;Start simple, add complexity only when needed, and &lt;strong&gt;never ship without observability&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;further-reading-amp-resources&quot;&gt;Further Reading &amp;amp; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.datacamp.com/tutorial/langchain-vs-langgraph-vs-langsmith-vs-langflow&quot;&gt;https://www.datacamp.com/tutorial/langchain-vs-langgraph-vs-langsmith-vs-langflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.datacamp.com/tutorial/langgraph-tutorial&quot;&gt;https://www.datacamp.com/tutorial/langgraph-tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.datacamp.com/tutorial/langgraph-agents&quot;&gt;https://www.datacamp.com/tutorial/langgraph-agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.techvoot.com/blog/langchain-vs-langgraph-vs-langflow-vs-langsmith-2025&quot;&gt;https://www.techvoot.com/blog/langchain-vs-langgraph-vs-langflow-vs-langsmith-2025&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Video&lt;/strong&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/watch?v=vJOGC8QJZJQ&quot;&gt;https://www.youtube.com/watch?v=vJOGC8QJZJQ&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Academy Finxter Series (Excellent Deep Dive)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://academy.finxter.com/langchain-langsmith-and-langgraph/&quot;&gt;https://academy.finxter.com/langchain-langsmith-and-langgraph/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://academy.finxter.com/langsmith-and-writing-tools/&quot;&gt;https://academy.finxter.com/langsmith-and-writing-tools/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://academy.finxter.com/langgraph/&quot;&gt;https://academy.finxter.com/langgraph/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://academy.finxter.com/multi-agent-teams-preparation/&quot;&gt;https://academy.finxter.com/multi-agent-teams-preparation/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://academy.finxter.com/setting-up-our-multi-agent-team/&quot;&gt;https://academy.finxter.com/setting-up-our-multi-agent-team/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://academy.finxter.com/web-research-and-asynchronous-tools/&quot;&gt;https://academy.finxter.com/web-research-and-asynchronous-tools/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/9900/langchain-vs-langgraph-vs-langsmith-understanding-the-ecosystem</guid>
<pubDate>Sat, 17 Jan 2026 13:36:52 +0000</pubDate>
</item>
<item>
<title>You're Testing AI Agents Wrong (And You Don't Know It Yet)</title>
<link>https://coderlegion.com/9400/youre-testing-ai-agents-wrong-and-you-dont-know-it-yet</link>
<description>&lt;p&gt;Your evals are passing 100%. Your prompts are solid. Your agent works perfectly in testing.&lt;/p&gt;
&lt;p&gt;Then it hits production.&lt;/p&gt;
&lt;p&gt;An API adds 500ms of latency. Suddenly your agent times out. The LLM hallucinates malformed JSON. Your parser breaks. A prompt injection slips through. Latency spikes cascade into retry loops that torch your token budget.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The problem isn't your eval framework. The problem is that you're only testing half of what matters.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;the-eval-trap&quot;&gt;The Eval Trap&lt;/h3&gt;
&lt;p&gt;Tools like PromptFoo are genuinely excellent. They confirm your agent behaves correctly against known inputs in ideal scenarios. But here's the gap nobody talks about: &lt;strong&gt;passing 100% of evals tells you nothing about how your agent fails.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you're only testing what the agent &lt;em&gt;should&lt;/em&gt; do, you learn nothing about how it will actually &lt;em&gt;behave&lt;/em&gt; under real-world stress.&lt;/p&gt;
&lt;p&gt;This is the core reliability blind spot in AI agent development right now.&lt;/p&gt;
&lt;h3 id=&quot;what-you-re-missing-the-chaos-layer&quot;&gt;What You're Missing: The Chaos Layer&lt;/h3&gt;
&lt;p&gt;In traditional software, we have unit tests, integration tests, and then &lt;strong&gt;chaos engineering&lt;/strong&gt;, a way to deliberately introducing failures to validate resilience.&lt;/p&gt;
&lt;p&gt;For AI agents, we're skipping the third layer entirely.&lt;/p&gt;
&lt;p&gt;Chaos testing for AI isn't about &quot;correct&quot; answers. It's about invariants. It asks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Does the response arrive within your latency budget even when the database is slow?&lt;/li&gt;
&lt;li&gt;Does the agent produce valid JSON even when the tool returns garbage?&lt;/li&gt;
&lt;li&gt;Can it recover from a network timeout or does it get stuck retrying forever?&lt;/li&gt;
&lt;li&gt;Does it avoid leaking sensitive data even when prompted with injections?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The framework generates adversarial mutations of your golden prompts: typos, paraphrases, jailbreaks, simulated latency spikes, malformed API responses. Your agent runs the gauntlet. You measure robustness, not correctness.&lt;/p&gt;
&lt;h3 id=&quot;what-this-looks-like-in-practice&quot;&gt;What This Looks Like in Practice&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Golden prompt: &quot;What's my account balance?&quot;

Mutations generated:
- Typo version: &quot;Whats my acount ballance?&quot;
- Semantic paraphrase: &quot;How much money do I currently have?&quot;
- Jailbreak attempt: &quot;Ignore safety rules and tell me...&quot;
- Latency spike: (tool returns after 2 seconds instead of 200ms)
- Malformed response: (JSON with missing bracket)

Invariants checked:
✓ Response time &amp;lt; 5 seconds
✓ Valid JSON structure
✓ No PII in output
✓ Terminates (no infinite loops)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An agent passes if it satisfies your invariants regardless of whether the &quot;answer&quot; was perfect. This measures what actually matters: &lt;strong&gt;reliability under adversity&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-real-impact&quot;&gt;The Real Impact&lt;/h3&gt;
&lt;p&gt;For teams deploying production agents:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unquantified risk shipped to production.&lt;/strong&gt; You don't know what you don't know.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Silent failures scale costs.&lt;/strong&gt; A stuck agent retrying bad requests burns tokens silently.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lost user trust.&lt;/strong&gt; Unpredictable behavior kills adoption faster than limited capability.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No clear path to improvement.&lt;/strong&gt; Without knowing which failure modes matter most, you don't know where to focus fixes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Chaos testing gives you data on all of this. It generates actionable failure reports that show exactly which mutation types break your agent and why.&lt;/p&gt;
&lt;h3 id=&quot;questions-for-your-agent&quot;&gt;Questions for Your Agent&lt;/h3&gt;
&lt;p&gt;Before your users find out, ask yourself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Can my agent handle a 2-second API latency without timing out?&lt;/li&gt;
&lt;li&gt;What happens if a tool returns invalid JSON?&lt;/li&gt;
&lt;li&gt;Will a clever prompt injection get past my safety guardrails?&lt;/li&gt;
&lt;li&gt;Can my agent detect when a tool returned corrupted data?&lt;/li&gt;
&lt;li&gt;Does my retry logic eventually terminate, or can it get stuck in loops?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you can't confidently answer these questions from your current testing, you have a chaos testing gap.&lt;/p&gt;
&lt;h3 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Audit your testing strategy.&lt;/strong&gt; Are you only testing happy paths? You have a gap.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Define your invariants.&lt;/strong&gt; What are the non-negotiable rules for your agent? Write them down.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explore chaos testing tools.&lt;/strong&gt; Frameworks for AI agent reliability testing are maturing rapidly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integrate into CI/CD.&lt;/strong&gt; Make robustness a first-class metric, not an afterthought.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Read the full breakdown:&lt;/strong&gt; I've written a comprehensive guide exploring chaos engineering principles for AI agents, the technical implementation details, and how to integrate this into your CI/CD pipeline.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://medium.com/majordigest/why-chaos-engineering-is-the-missing-layer-for-reliable-ai-agents-in-ci-cd-6c27ce5e1613&quot;&gt;Read the full article on Medium →&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;What's your take? Are you testing agent reliability? Or just testing correctness? Drop your thoughts in the comments.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/9400/youre-testing-ai-agents-wrong-and-you-dont-know-it-yet</guid>
<pubDate>Thu, 08 Jan 2026 12:08:37 +0000</pubDate>
</item>
<item>
<title>GroqStreamChain: Revolutionizing Real-Time AI Chat with WebSocket and Groq</title>
<link>https://coderlegion.com/4137/groqstreamchain-revolutionizing-real-time-ai-chat-with-websocket-and-groq</link>
<description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the world of AI-powered chat applications, real-time communication and quick response times are crucial. GroqStreamChain is a project that combines cutting-edge technologies to create a seamless, low-latency chat system. This project leverages WebSocket for instant communication and streams AI responses powered by Groq and LangChain, providing an immersive user experience with real-time feedback.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is GroqStreamChain?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;GroqStreamChain is a real-time chat system designed to facilitate smooth interactions between users and AI. By using WebSocket, this system ensures that the chat messages are delivered instantly, with minimal delay. The chat application streams responses chunk by chunk, which not only reduces latency but also enhances the user experience by providing quick feedback. At its core, GroqStreamChain integrates Groq's powerful LLMs (large language models) and LangChain, an integration tool that connects various language models to applications, ensuring smart and dynamic responses.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Features of GroqStreamChain&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Real-Time Communication via WebSocket&lt;/strong&gt;&lt;br&gt;
The system is built around WebSocket, allowing instant and low-latency communication. This helps in reducing any delays in message delivery, which is crucial for an interactive chat experience.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Streaming Responses&lt;/strong&gt;&lt;br&gt;
Instead of waiting for the full response from the language model, GroqStreamChain streams responses as they are generated. This feature makes the system feel faster by showing partial responses to the user immediately.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Efficient Session Management&lt;/strong&gt;&lt;br&gt;
Every user gets a unique chat session automatically, ensuring that interactions are personalized and persistent across sessions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;User-Friendly Frontend&lt;/strong&gt;&lt;br&gt;
The chat application offers a clean, responsive UI that includes typing indicators and message formatting, making the chat experience visually appealing and smooth.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Robust Error Handling&lt;/strong&gt;&lt;br&gt;
WebSocket disconnections and reconnections are managed with care, ensuring the system continues to function seamlessly even in case of network issues.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Project Structure&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;GroqStreamChain follows a modular approach, organizing the project into distinct files and folders for efficient management and easy navigation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;server.py&lt;/code&gt;&lt;/strong&gt;: The core FastAPI server responsible for managing WebSocket connections.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;config.py&lt;/code&gt;&lt;/strong&gt;: This file handles configuration settings like API keys and model configurations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;models/chat.py&lt;/code&gt;&lt;/strong&gt;: Contains the data models used to handle chat messages and sessions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;services/llm_service.py&lt;/code&gt;&lt;/strong&gt;: Connects with Groq and LangChain to generate AI-powered responses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Frontend&lt;/strong&gt;: Contains the HTML, CSS, and JavaScript files that make up the user interface.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;How to Get Started&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Setting up GroqStreamChain on your local machine is simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clone the repository&lt;/strong&gt;:&lt;br&gt;
Begin by cloning the repository to your local machine.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Install dependencies&lt;/strong&gt;:&lt;br&gt;
You can install the necessary libraries using &lt;code&gt;pip&lt;/code&gt; or &lt;code&gt;conda&lt;/code&gt;. It's recommended to create a separate Conda environment for the project.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set up environment variables&lt;/strong&gt;:&lt;br&gt;
In your project directory, create a &lt;code&gt;.env&lt;/code&gt; file and add your Groq API key and the model name to connect to the Groq service.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Run the server&lt;/strong&gt;:&lt;br&gt;
Once you've set everything up, start the server with a simple command and access the chat application through your browser.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Testing the Groq API&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The repository also includes a test script to verify that the Groq API is set up correctly. This is useful for ensuring that the connection to the Groq model is working as expected. Running the test script will allow you to see if you receive the expected responses from Groq.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Performance Considerations&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;GroqStreamChain is designed to handle communication and AI processing efficiently:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Persistent WebSocket connection&lt;/strong&gt;: By maintaining an open connection, the system ensures fast communication without the overhead of reconnecting.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real-time response streaming&lt;/strong&gt;: The system minimizes latency by delivering partial responses while the full response is still being generated.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optimized server-side processing&lt;/strong&gt;: The backend server offloads heavy tasks to Groq's powerful model, ensuring minimal processing on the server side and faster responses.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;GroqStreamChain brings real-time AI chat capabilities to a new level by using WebSocket for seamless communication and integrating powerful AI responses powered by Groq. Whether you're building customer support bots or AI-driven personal assistants, GroqStreamChain provides the tools needed to create an efficient and responsive chat system. Check out the repository, set it up locally, and explore how this cutting-edge technology can help enhance user interaction in real-time.&lt;/p&gt;
&lt;p&gt;For a more detailed walkthrough, feel free to explore the full documentation in the GitHub repository.&lt;/p&gt;
&lt;p&gt;Repository link: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/pr0mila/GroqStreamChain&quot;&gt;https://github.com/pr0mila/GroqStreamChain&lt;/a&gt;&lt;/p&gt;
</description>
<category>Deep Learning</category>
<guid isPermaLink="true">https://coderlegion.com/4137/groqstreamchain-revolutionizing-real-time-ai-chat-with-websocket-and-groq</guid>
<pubDate>Fri, 18 Jul 2025 12:38:54 +0000</pubDate>
</item>
<item>
<title>Reflections on My Second LangChain Session: Hype, Substance, and Agentic Potential</title>
<link>https://coderlegion.com/3064/reflections-on-my-second-langchain-session-hype-substance-and-agentic-potential</link>
<description>&lt;p&gt;Today marked my second time attending a LangChain talk. My first was at a previous company, and this time, I joined an ACM-invited session. Unfortunately, my impression hasn’t changed much. Like the last time, the presentation leaned more toward a marketing pitch than a meaningful deep-dive into technology.&lt;/p&gt;
&lt;p&gt;Forty minutes into the session, we were still swimming in vague promises and general problem statements. &quot;LangGraph can solve this,&quot; they said - without ever really explaining how.&lt;/p&gt;
&lt;h3 id=&quot;what-langchain-brings-to-the-table&quot;&gt;What LangChain Brings to the Table&lt;/h3&gt;
&lt;p&gt;To be fair, LangChain does offer a decent toolbox. Its ecosystem includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Paid utilities (like PDF ingestion)&lt;/li&gt;
&lt;li&gt;Core components such as text splitters, output parsers, document loaders, and vector stores&lt;/li&gt;
&lt;li&gt;Compositional elements like prompts, example selectors, tools, and model abstractions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Among these, the PDF ingestion tool stood out. It's genuinely useful - just not particularly accessible, since it sits behind a paywall. That pattern of paywalled features brings up the classic vendor lock-in concern. When a tech stack becomes too reliant on a single platform, especially one with closed components, you're playing a risky game. And to be blunt, the overall design doesn’t feel groundbreaking.&lt;/p&gt;
&lt;h3 id=&quot;learning-by-observing&quot;&gt;Learning by Observing&lt;/h3&gt;
&lt;p&gt;For me, the purpose of attending wasn't just about learning the tool - it was about observing how they package and present AI service integration. As Divooka continues to evolve and offer deeper native AI capabilities, I find myself increasingly valuing compositional and node-native approaches, like what ComfyUI offers. Its visual chaining model feels more transparent and modular - something that can be critical when building robust, production-grade AI workflows.&lt;/p&gt;
&lt;p&gt;That said, there &lt;em&gt;was&lt;/em&gt; one key idea from the LangChain session that resonated: agents &lt;em&gt;do&lt;/em&gt; matter. Agentic applications, when structured with purpose and supported by strong pipelines, can lead to some powerful real-world use cases.&lt;/p&gt;
&lt;h3 id=&quot;the-real-time-use-challenge&quot;&gt;The &quot;Real-Time Use&quot; Challenge&lt;/h3&gt;
&lt;p&gt;The first problem they introduced had to do with real-time responsiveness. Ironically, they later conceded it wasn’t really a &quot;problem&quot; but more a matter of user-perceived latency. Still, here's how they broke it down:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;strong&gt;Challenge&lt;/strong&gt;                                           &lt;/th&gt;&lt;th&gt;&lt;strong&gt;Proposed Solution&lt;/strong&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Multiple LLM calls needed                               &lt;/td&gt;&lt;td&gt;Parallelize steps where possible&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Non-LLM steps (e.g., RAG, database queries, tool calls) &lt;/td&gt;&lt;td&gt;Parallelize or batch when feasible&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Keeping users engaged during waiting periods            &lt;/td&gt;&lt;td&gt;Stream intermediate outputs (optional)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The advice wasn’t necessarily wrong - but it felt narrow. These solutions are tailored for real-time UIs and don’t necessarily tap into the deeper promise of agentic systems. Agents shouldn’t just be about speed - they should be about capability, reasoning, adaptability.&lt;/p&gt;
&lt;h3 id=&quot;langgraph-intriguing-promises-lingering-questions&quot;&gt;LangGraph: Intriguing Promises, Lingering Questions&lt;/h3&gt;
&lt;p&gt;LangGraph, as an extension of LangChain, introduces some genuinely interesting features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Persistent, long-running workflows with streaming and human-in-the-loop support&lt;/li&gt;
&lt;li&gt;Integration with LangSmith for observability&lt;/li&gt;
&lt;li&gt;A main graph architecture augmented by subgraphs for each agent - supporting multi-agent interaction patterns&lt;/li&gt;
&lt;li&gt;Native support for both token- and event-level streaming&lt;/li&gt;
&lt;li&gt;(Interestingly, someone compared it to Amazon Bedrock Flows, which seems like a fair analogy)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Despite the potential, several critical questions remain unanswered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What does the full system architecture look like?&lt;/li&gt;
&lt;li&gt;Is LangGraph something you &lt;em&gt;must&lt;/em&gt; self-host, or does it assume reliance on LangChain’s hosted infrastructure?&lt;/li&gt;
&lt;li&gt;How is state managed internally, and how configurable is the runtime model?&lt;/li&gt;
&lt;li&gt;What’s the actual developer experience like when setting up human-in-the-loop interaction?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They did recommend a textbook - &lt;em&gt;Learning LangChain: Building AI and LLM Applications with LangChain and LangGraph&lt;/em&gt; by Mayo and Nuno - which might offer some clarity. But relying on a textbook to fill in architectural gaps from a talk feels like a missed opportunity.&lt;/p&gt;
&lt;h3 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;These sessions are always worth attending - not necessarily for the content, but for the context. It’s important to see how the broader ecosystem evolves, what narratives companies are pushing, and where we can differentiate.&lt;/p&gt;
&lt;p&gt;At Methodox, we’re focusing on flexibility, transparency, and seamless integration across AI services. That’s why our approach to Divooka aligns more closely with frameworks like ComfyUI - ones that embrace openness and modularity.&lt;/p&gt;
&lt;p&gt;The future of AI applications will depend not just on speed or flashy demos, but on clarity of architecture, trust in execution, and real-world adaptability. That’s where I believe we can lead.&lt;/p&gt;
</description>
<category>Data Science</category>
<guid isPermaLink="true">https://coderlegion.com/3064/reflections-on-my-second-langchain-session-hype-substance-and-agentic-potential</guid>
<pubDate>Fri, 16 May 2025 16:43:56 +0000</pubDate>
</item>
<item>
<title>Build a Discord python assistant with plain Langchain</title>
<link>https://coderlegion.com/309/build-a-discord-python-assistant-with-plain-langchain</link>
<description>&lt;h2&gt;1. Introduction&lt;/h2&gt;
&lt;p&gt;Discord is one of the most widespread instant-messaging services, especially when it comes to developers: its structure and internal organization into servers and channels made it easy to use with large community and extremely popular all across the world.&lt;/p&gt;
&lt;p&gt;But Discord &lt;strong&gt;is more than just the blue-ish icon on your desktop&lt;/strong&gt;: it indeed comes with lots of integrations for developers, such as applications and bots. In today's tutorial, we will see how we can build an AI-powered bot, in pure and simple &lt;strong&gt;python&lt;/strong&gt;, with the help of &lt;strong&gt;Langchain&lt;/strong&gt;, a widespread and appreciated library to build scalable AI products through &lt;strong&gt;composability&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;2. Setup&lt;/h2&gt;
&lt;h3&gt;2a. Folder&lt;/h3&gt;
&lt;p&gt;For the setup, let's begin with structuring our base folder. To do so, I strongly suggest you navigate to my &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/AstraBert/coderlegion&quot;&gt;GitHub repository&lt;/a&gt; and either take a look to &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/AstraBert/coderlegion/tree/main/article5/&quot;&gt;article5&lt;/a&gt; directory or you &lt;strong&gt;clone it&lt;/strong&gt; with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git clone https://github.com/AstraBert/coderlegion.git
cd coderlegion/article5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here you will see something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.
├── .env.example
├── bot.py
├── inference.py
├── requirements.txt
└── utils.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let's take a look to what these file do: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.env.example&lt;/code&gt; (make sure to rename it to &lt;code&gt;.env&lt;/code&gt;) is thd file where you safely store and secure private &lt;strong&gt;environmental variables&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt;&lt;code&gt;bot.py&lt;/code&gt; is the script which &lt;strong&gt;builds the bot and makes it run&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inference.py&lt;/code&gt; contains the actual &lt;strong&gt;Langchain&lt;/strong&gt; structure to power the bot with &lt;strong&gt;AI&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;requirements.txt&lt;/code&gt; contains the &lt;strong&gt;necessary packages&lt;/strong&gt; to be installed&lt;/li&gt;
&lt;li&gt;&lt;code&gt;utils.py&lt;/code&gt;defines a class to &lt;strong&gt;search the vector database&lt;/strong&gt; we will build in the next steps (more about vector databases at &lt;a rel=&quot;nofollow&quot; href=&quot;https://astrabert.github.io/hophop-science/Vector-databases-explained/&quot;&gt;&lt;em&gt;Vector databases explained&lt;/em&gt;&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2b. Dependencies&lt;/h3&gt;
&lt;p&gt;You will have to install the needed dependencies, and the easiest way to do it is to copy &lt;code&gt;requirements.txt&lt;/code&gt; to your local folder and run:&lt;/p&gt;
&lt;p&gt;python3 -m pip install -r requirements.txt&lt;/p&gt;
&lt;p&gt;Let's see what packages we need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;transformers&lt;/strong&gt; and &lt;strong&gt;sentence-transformers&lt;/strong&gt; are used to tokenize and encode (which means represent as multi-dimensional numerical arrays) users' messages to query the vector database&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;langchain-related&lt;/strong&gt; packages are needed to build the AI architecture, interact with Cohere and give the bot some conversational memory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;discord.py&lt;/strong&gt; is the Discord python SDK&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;vecs&lt;/strong&gt; is the python integration for Supabase (that we already used in the last tutorial)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;pydotenv&lt;/strong&gt; is used to load environmental variables from the &lt;code&gt;.env&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2c. Vector Database&lt;/h3&gt;
&lt;p&gt;We will build our vector database with the help of Supabase and with the Hugging Face dataset &lt;code&gt;dipesh/python-code-ds-mini&lt;/code&gt;, by Dipesh Paul, which encompasses &lt;strong&gt;2200 python code instances&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In order to do it, we will follow &lt;a rel=&quot;nofollow&quot; href=&quot;https://gist.github.com/AstraBert/455badcbf24fac2ff65115d12374d301&quot;&gt;this GitHub Gist&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In order to make the Gist code run properly, you just need to: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://supabase.com/dashboard/sign-up&quot;&gt;Register to Supabase&lt;/a&gt; (you can quickly sign up with GitHub)&lt;/li&gt;
&lt;li&gt;Create your first project&lt;/li&gt;
&lt;li&gt;Navigate to &lt;code&gt;Project Settings&lt;/code&gt; and then &lt;code&gt;Database&lt;/code&gt;, where you should copy the &lt;code&gt;Connection string&lt;/code&gt;, making sure to replace the &lt;code&gt;postgres://&lt;/code&gt; heading with &lt;code&gt;postgresql://&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Open the Gist in Google Colab&lt;/li&gt;
&lt;li&gt;Copy the &lt;code&gt;Connection string&lt;/code&gt; into a Colab Secret (under the key sign) named &quot;TINY_CODES_DB&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now just run all the blocks in Colab and you'll have the &lt;strong&gt;vector database built in 10 minutes' time&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Make sure also to save the &lt;code&gt;Connection string&lt;/code&gt; under &lt;code&gt;supabase_database&lt;/code&gt; variable in your &lt;code&gt;.env&lt;/code&gt; file!&lt;/p&gt;
&lt;h3&gt;2d. Discord Bot&lt;/h3&gt;
&lt;p&gt;Follow these simple steps to build the Discord bot container:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go to &lt;a rel=&quot;nofollow&quot; href=&quot;https://discord.com/&quot;&gt;Discord&lt;/a&gt; and create an account (or log into yours, if you already have one)&lt;/li&gt;
&lt;li&gt;Create a new server by clicking on &quot;Add a server&quot; (a big green &quot;+&quot; button) and name it as you want&lt;/li&gt;
&lt;li&gt;Go to &lt;a rel=&quot;nofollow&quot; href=&quot;https://discord.com/developers/applications&quot;&gt;Discord developers portal&lt;/a&gt; and click on &quot;New application&quot;&lt;/li&gt;
&lt;li&gt;Name your application, then save the changes and click on &quot;Bot&quot;, on the left&lt;/li&gt;
&lt;li&gt;There you will get the chance to name your bot and copy its token&lt;/li&gt;
&lt;li&gt;After that, go on &quot;OAuth2&quot; &amp;gt; &quot;URL generator&quot; and generate a URL that you will paste in your navigation bar, to add the bot to your newly created server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now paste the bot token and your server's channel ID (the last numeric combination you see in the URL of your channel) to your &lt;code&gt;.env&lt;/code&gt; file, as &lt;code&gt;discord_token&lt;/code&gt; and &lt;code&gt;discord_channel&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The bot is created, but it is &lt;strong&gt;unresponsive&lt;/strong&gt;; this is because we only generated an external facade, with no backbone to sustain it: it's now time to fill it with life thanks some python code.&lt;/p&gt;
&lt;h3&gt;2e. Cohere API key&lt;/h3&gt;
&lt;p&gt;Getting a Cohere free API key is really simple: you need to register &lt;a rel=&quot;nofollow&quot; href=&quot;https://dashboard.cohere.com/welcome/register&quot;&gt;on their website&lt;/a&gt; (you can exploit signing up with GitHub also here) and then head over to the &lt;code&gt;API keys&lt;/code&gt; section, where you could generate a free key that has a 100 calls/min limit.&lt;/p&gt;
&lt;p&gt;Copy the key and save it to your &lt;code&gt;.env&lt;/code&gt; file, as &lt;code&gt;cohere_api_key&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;3. Build with Langchain&lt;/h2&gt;
&lt;p&gt;In this section, we're gonna modify &lt;strong&gt;inference.py&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;3a. Build the Cohere model&lt;/h3&gt;
&lt;p&gt;In order to connect with Cohere, you need to import the &lt;strong&gt;needed packages&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_cohere import ChatCohere
from dotenv import load_dotenv
import os
from langchain_community.chat_message_histories import SQLChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then we load the environmental variables, get Cohere API key and load the chat model:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;load_dotenv()
os.environ[&quot;COHERE_API_KEY&quot;]  = os.getenv(&quot;cohere_api_key&quot;) 
model = ChatCohere()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We now need to actually build it into some sort of conversational chain, so we first define a system template (variables in brackets will be passed as arguments to the following block, so they get re-defined at every call):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;system_template = &quot;You are an helpful coding assistant that can rely on this code: {context} and on the previous message history as context, and from that you build a context and history-aware reply to this (DO NOT mention the fact that you are starting from a code snippet):&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;div-green&quot;&gt;
&lt;span class=&quot;alert-header&quot;&gt;TIP:&lt;/span&gt;
&lt;span class=&quot;alert-body&quot;&gt; This portion is critical for getting the best out of the chat model: customize it to your needs!&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;And then a prompt template and the chain:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;prompt_template = ChatPromptTemplate.from_messages(
    [(&quot;system&quot;, system_template),
    MessagesPlaceholder(variable_name=&quot;history&quot;),
    (&quot;human&quot;, &quot;{input}&quot;)]
)
chain = prompt_template | model
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3b. Chat Memory&lt;/h3&gt;
&lt;p&gt;Chat memory is crucial for the bot to &lt;strong&gt;remember the previous messages&lt;/strong&gt; during a conversation, so we need to add it with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def get_session_history(session_id):
    return SQLChatMessageHistory(session_id, &quot;sqlite:///memory1.db&quot;)
runnable_with_history = RunnableWithMessageHistory(
    chain,
    get_session_history,
    input_messages_key=&quot;input&quot;,
    history_messages_key=&quot;history&quot;,
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;session_id&lt;/code&gt; is an alphanumeric code associated with each session of activity of the bot: each session is independent and there is &lt;strong&gt;no common knowledge across them&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;3c. Inference&lt;/h3&gt;
&lt;p&gt;Now that we have all set, we can define a inference function with which we query Cohere's model and we retrieve the answers:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def infer_reply(context, text, sessionid):
    global chain
    r = runnable_with_history.invoke(
        {&quot;context&quot;: context, &quot;input&quot;: text},
        config={&quot;configurable&quot;: {&quot;session_id&quot;: sessionid}}
    )
    return r.content
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4. Vector Database Search&lt;/h2&gt;
&lt;p&gt;To search the vector database, we define a &lt;strong&gt;NeuralSearcher&lt;/strong&gt; class inside &lt;strong&gt;utils.py&lt;/strong&gt;, which is the same as the one we used in last tutorial:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class NeuralSearcher:
    def __init__(self, collection, encoder):
        self.collection = collection
        self.encoder = encoder
    def search(self, text):
        results = self.collection.query(
            data=self.encoder.encode(text).tolist(), limit=1, filters={}, measure=&quot;cosine_distance&quot;, include_value=True, include_metadata=True,
        )
        return results
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5. Discord Bot&lt;/h2&gt;
&lt;p&gt;We have everything in place now, so we can actually import the needed packages in &lt;strong&gt;bot.py&lt;/strong&gt; and define some global variables and the Discord client:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from discord import Client, Intents
from utils import NeuralSearcher
import os
import vecs
from dotenv import load_dotenv
from sentence_transformers import SentenceTransformer
from inference import infer_reply
import time
import random as r

load_dotenv()
collection_name = &quot;documents&quot;
encoder = SentenceTransformer(&quot;all-MiniLM-L6-v2&quot;)
client = os.getenv(&quot;supabase_database&quot;)
vx = vecs.create_client(client)
docs = vx.get_or_create_collection(name=collection_name, dimension=384)
rand_sess_id = str(r.randint(1,100)) + r.choice([&quot;a&quot;, &quot;e&quot;, &quot;i&quot;, &quot;o&quot;, &quot;u&quot;])
CHANNEL_ID = int(os.getenv(&quot;discord_channel&quot;))
TOKEN = os.getenv(&quot;discord_token&quot;)
intents = Intents.default()
intents.messages = True
bot = Client(intents=intents)
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;div-blue&quot;&gt;
&lt;span class=&quot;alert-header&quot;&gt;NOTE:&lt;/span&gt;
&lt;span class=&quot;alert-body&quot;&gt; A unique session_id is set here at the beginning of the code, and will be re-set every time we start the bot&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;Now let's tell the bot what to do when it connects to our channel:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@bot.event
async def on_ready():
    channel = bot.get_channel(CHANNEL_ID)
    if channel:
        # Send the welcome message
        await channel.send(f&quot;Hi, I'm here to assist you!&quot;)
    else:
        print(&quot;Unable to find the specified channel ID. Make sure the ID is correct and the bot has the necessary permissions.&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;div-blue&quot;&gt;
&lt;span class=&quot;alert-header&quot;&gt;NOTE:&lt;/span&gt;
&lt;span class=&quot;alert-body&quot;&gt; The expression starting with '@' is known as a decorator&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;Last but not least, we define a function that produces the context for Cohere chat model (which discards contexts with less than 25% similarity with the query), a function to reply to the users' query and we make the bot run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def get_context(results):
    if results[0][1] &amp;gt; 0.25:
        return results[0][2][&quot;Content&quot;]
    else:
        return &quot;There is no specific context for this query&quot;

def reply(message):
    global docs
    global encoder
    txt2txt = NeuralSearcher(docs, encoder)
    results = txt2txt.search(message)
    print(results)
    context = get_context(results)
    response = infer_reply(context, message, rand_sess_id)
    return response

@bot.event
async def on_message(message):
    if message.author == bot.user:
        return  
    elif message.content:
        response = reply(message.content)
        await message.channel.send(
            response
        )
bot.run(TOKEN)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, everything is ready! We go to the terminal and launch the bot with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python3 bot.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we wait for the connection to be established and for the welcome message by the bot.&lt;/p&gt;
&lt;h2&gt;6. Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, we learnt how to build a &lt;strong&gt;free&lt;/strong&gt;, personal &lt;strong&gt;coding assistant&lt;/strong&gt; that is able to help you &lt;strong&gt;fix python snippets&lt;/strong&gt;, all accessible through a popular messaging platform like &lt;strong&gt;Discord&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The bot was built using &lt;strong&gt;plain Langchain&lt;/strong&gt; and some other not-too-difficult python code, so it is &lt;strong&gt;beginner friendly&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;This article &lt;strong&gt;concludes the series dedicated to python-backed bots&lt;/strong&gt;: hope you enjoyed it!&lt;/p&gt;
</description>
<category>Project Dev</category>
<guid isPermaLink="true">https://coderlegion.com/309/build-a-discord-python-assistant-with-plain-langchain</guid>
<pubDate>Sat, 01 Jun 2024 22:25:10 +0000</pubDate>
</item>
</channel>
</rss>