Introduction
In Accounting and Financial Management, a critical disconnect exists between how stakeholders ask questions and how financial data is structured. A CFO might ask, "Why are our margins squeezing?" while the underlying ERP data only contains GL codes like 6200-COGS and metadata tags like variance_unfavorable. Standard RAG systems fail here because vector similarity matches keywords, not business intent. To solve this, enterprises must treat historical analyst commentary ("review text") and enriched ledger descriptions as an intent alignment layer. This article demonstrates how to operationalize these unstructured assets to bridge the semantic gap. We provide a complete end-to-end implementation using LangGraph and Chroma, featuring a multi-agent architecture where a dedicated "Intent Alignment Agent" dynamically maps natural language queries to precise financial structures before retrieval, ensuring that variance analysis, audit inquiries, and management reporting return contextually accurate results rather than keyword-matched noise.
Core Concept: The Intent Alignment Layer
Before diving into code, it is essential to understand how review text and descriptions drive alignment:
Review Text as Query Expansion: Historical analyst notes (e.g., Q3 earnings call transcripts, variance commentary emails) contain the exact phrasing humans use to describe financial phenomena. These are embedded alongside structured data to create "semantic anchors." When a user asks about "margin squeeze," the system retrieves the analyst note explaining that margin squeeze = COGS increase + flat pricing, then uses those terms to query the structured ledger.
Enriched Descriptions as Metadata Bridges: Raw GL descriptions (
6200 - Cost of Goods Sold) are insufficient. Enriched descriptions add business context:"6200-COGS: Direct manufacturing costs including raw materials, direct labor, and factory overhead. Variance driver: commodity price fluctuations."This enrichment is stored as both embedding text AND structured metadata, enabling hybrid search that understands both the accounting term and the business phenomenon.Feedback Loop Integration: When analysts correct agent responses (e.g., "No, I meant operating margin, not gross margin"), these corrections are stored as negative examples in a separate collection. The Intent Alignment Agent consults this collection to avoid repeating misalignments.
End-to-End Implementation: "FinAlign" – Intent-Aware Financial Analysis Platform
Use Case Scenario
A regional manufacturing CFO asks during monthly review: "What's driving the margin compression in our Industrial division this quarter compared to budget?"
This requires:
Intent Alignment Agent: Maps "margin compression" →
{gross_margin_variance, cogs_overrun, pricing_shortfall}using historical review text.Ledger Retrieval Agent: Queries actuals vs. budget with aligned GL codes and division filters.
Variance Commentary Agent: Retrieves relevant analyst notes and prior-period explanations.
Synthesis Agent: Combines quantitative data with qualitative context, citing sources.
Architecture Diagram

Step 1: Define Financial State with Intent Alignment Fields
from typing import Annotated, TypedDict, Literalfrom langgraph.graph.message import add_messages
from pydantic import BaseModel, Field
class AlignedIntent(BaseModel):
"""Structured output from intent alignment"""
business_concept: str = Field(description="Mapped financial concept")
gl_codes: list[str] = Field(description="Relevant GL account codes")
variance_drivers: list[str] = Field(description="Known drivers from review text")
confidence: float = Field(ge=0.0, le=1.0)
class FinancialAnalysisState(TypedDict):
messages: Annotated[list, add_messages]
division: str | None
fiscal_period: str | None
aligned_intent: AlignedIntent | None
ledger_data: list[dict] | None
review_excerpts: list[str] | None
feedback_warnings: list[str] | None # Past corrections to avoid
final_response: str | NoneStep 2: Configure Chroma Collections for Intent Alignment
import chromadb
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
client = chromadb.PersistentClient(path="./chroma_fin_align")
# Collection 1: Analyst Review Text (intent anchors)
review_collection = client.get_or_create_collection(
name="analyst_reviews_v2025Q3",
metadata={"hnsw:M": 32, "content_type": "commentary"}
)
# Collection 2: Enriched GL Descriptions (semantic bridge)
gl_desc_collection = client.get_or_create_collection(
name="enriched_gl_descriptions",
metadata={"hnsw:M": 48, "content_type": "chart_of_accounts"}
)
# Collection 3: Feedback/Corrections (negative alignment)
feedback_collection = client.get_or_create_collection(
name="analyst_feedback",
metadata={"hnsw:M": 16, "content_type": "corrections"}
)
review_store = Chroma(client=client, collection_name="analyst_reviews_v2025Q3",
embedding_function=OpenAIEmbeddings(model="text-embedding-3-small"))
gl_desc_store = Chroma(client=client, collection_name="enriched_gl_descriptions",
embedding_function=OpenAIEmbeddings(model="text-embedding-3-small"))
feedback_store = Chroma(client=client, collection_name="analyst_feedback",
embedding_function=OpenAIEmbeddings(model="text-embedding-3-small"))
Step 3: Implement the Intent Alignment Agent
This is the core innovation — it uses review text and descriptions to translate business language into financial structure before any ledger query occurs.
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
async def intent_alignment_agent(state: FinancialAnalysisState) -> dict:
"""Maps natural language to financial structure using reviews + GL descriptions"""
query = state["messages"][-1].content
# 1. Retrieve relevant analyst review excerpts (intent anchors)
reviews = review_store.similarity_search(query=query, k=5)
review_context = "\n---\n".join([r.page_content for r in reviews])
# 2. Retrieve enriched GL descriptions matching the concept
gl_matches = gl_desc_store.similarity_search(query=query, k=8)
gl_context = "\n".join([
f"[{r.metadata['gl_code']}] {r.page_content}" for r in gl_matches
])
# 3. Check feedback history for known misalignments to avoid
warnings = feedback_store.similarity_search(query=query, k=3)
feedback_warnings = [w.page_content for w in warnings
if w.metadata.get("correction_type") == "intent_mismatch"]
# 4. LLM synthesizes alignment using all three signals
alignment_prompt = f"""You are a financial intent alignment specialist.
USER QUERY: {query}
ANALYST REVIEW EXCERPTS (show how humans describe this concept):
{review_context}
ENRICHED GL DESCRIPTIONS (structured financial mapping):
{gl_context}
KNOWN MISALIGNMENTS TO AVOID (from past corrections):
{chr(10).join(feedback_warnings) if feedback_warnings else "None"}
Map the user's business language to precise financial structure.
Return JSON matching the AlignedIntent schema."""
response = await llm.with_structured_output(AlignedIntent).ainvoke([
SystemMessage(content=alignment_prompt),
HumanMessage(content=query)
])
return {
"aligned_intent": response,
"feedback_warnings": feedback_warnings,
"review_excerpts": [r.page_content for r in reviews[:3]]
}

Join the conversation! Your thoughts help the community grow.