<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Anders Swanson</title>
    <description>The latest articles on DEV Community by Anders Swanson (@anders_swanson_ee86991e8b).</description>
    <link>https://dev.to/anders_swanson_ee86991e8b</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3181148%2F6193d2d4-3d11-489f-9a5e-085b23a772c6.jpg</url>
      <title>DEV Community: Anders Swanson</title>
      <link>https://dev.to/anders_swanson_ee86991e8b</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anders_swanson_ee86991e8b"/>
    <language>en</language>
    <item>
      <title>Agent Memory with LangChain4j and Oracle AI Database</title>
      <dc:creator>Anders Swanson</dc:creator>
      <pubDate>Wed, 22 Apr 2026 17:22:17 +0000</pubDate>
      <link>https://dev.to/oracledevs/agent-memory-with-langchain4j-and-oracle-ai-database-27bl</link>
      <guid>https://dev.to/oracledevs/agent-memory-with-langchain4j-and-oracle-ai-database-27bl</guid>
      <description>&lt;p&gt;One of the quickest ways to make an impressive agent demo is to prepare a clever prompt. One of the quickest ways to make that same agent fall apart in production is to give it no durable memory.&lt;/p&gt;

&lt;p&gt;In this article, we'll build a small, memory-backed assistant with &lt;a href="https://github.com/langchain4j/langchain4j" rel="noopener noreferrer"&gt;LangChain4j&lt;/a&gt; and Oracle AI Database. The assistant can search prior incidents, runbooks, decisions, and shift handoffs to answer questions. It can write new memories back to the database so they become searchable in any session. Additionally, all user, agent, and tool messages are logged to database table for observability and auditing.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Database feature overview&lt;/li&gt;
&lt;li&gt;Run the sample&lt;/li&gt;
&lt;li&gt;Chat Memory vs Durable Memory&lt;/li&gt;
&lt;li&gt;Hybrid retrieval: semantic + full-text search&lt;/li&gt;
&lt;li&gt;Lightweight reranking&lt;/li&gt;
&lt;li&gt;LangChain4j agent&lt;/li&gt;
&lt;li&gt;Memory writeback&lt;/li&gt;
&lt;li&gt;Recording user, agent, and tool messages&lt;/li&gt;
&lt;li&gt;Why database memory is useful for agents&lt;/li&gt;
&lt;li&gt;Code pointers&lt;/li&gt;
&lt;li&gt;Where you can take this next&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Database feature overview
&lt;/h4&gt;

&lt;p&gt;The agent is built with modern Oracle AI Database features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;persistent &lt;code&gt;JSON&lt;/code&gt; memory documents in Oracle AI Database&lt;/li&gt;
&lt;li&gt;vector embeddings in a &lt;code&gt;VECTOR&lt;/code&gt; column&lt;/li&gt;
&lt;li&gt;Oracle Text search over the same JSON document&lt;/li&gt;
&lt;li&gt;hybrid ranking that blends semantic and exact-match retrieval&lt;/li&gt;
&lt;li&gt;append-only transcript logging by conversation ID&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using these features, the agent (a fictional operations assistant) can answer question about runbooks, incident reviews, change requests, and shift handoffs from its persistent memory. Because the memory is database backed, multiple agents from concurrent sessions may access the same data safely.&lt;/p&gt;

&lt;h4&gt;
  
  
  Run the sample
&lt;/h4&gt;

&lt;p&gt;You will need Java 21+, Maven, Docker, and an &lt;a href="https://platform.openai.com/" rel="noopener noreferrer"&gt;OpenAI API Key&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;From the &lt;a href="https://github.com/andersswanson/oracle-ai-database-examples/tree/main/langchain4j-agent-memory" rel="noopener noreferrer"&gt;module root&lt;/a&gt;, run the tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your key&amp;gt;
mvn &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run the live terminal app using your database connection string and user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your key&amp;gt;
mvn compile &lt;span class="nb"&gt;exec&lt;/span&gt;:java &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-Dexec&lt;/span&gt;.args&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"jdbc:oracle:thin:@localhost:1521/freepdb1 testuser testpwd"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once it starts, try prompts like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;What happened during the checkout incident after CHG2145?&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Which runbook section should I use for the checkout rollback?&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Draft a next-shift handoff and remember it.&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Chat Memory vs Durable Memory
&lt;/h4&gt;

&lt;p&gt;Chat memory and durable memory solve different problems. Operational memory has different requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it should survive process restarts&lt;/li&gt;
&lt;li&gt;it should be queryable across conversations from distributed, concurrent agents&lt;/li&gt;
&lt;li&gt;it should support structured metadata like service, environment, incident ID, and change ticket&lt;/li&gt;
&lt;li&gt;it should be searchable both semantically and exactly&lt;/li&gt;
&lt;li&gt;it should allow writeback when the agent learns something worth preserving&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That starts to look a lot more like a database problem than a prompt engineering problem.&lt;/p&gt;

&lt;h4&gt;
  
  
  Hybrid retrieval: semantic + full-text search
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvjj8zm4u2n7p6vt8zr5v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvjj8zm4u2n7p6vt8zr5v.png" alt="Hybrid search" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/andersswanson/oracle-ai-database-examples/blob/main/langchain4j-agent-memory/src/main/java/dev/andersswanson/oracle/langchain4jmemory/MemoryRepository.java" rel="noopener noreferrer"&gt;&lt;code&gt;MemoryRepository&lt;/code&gt;&lt;/a&gt; runs two queries, which are fused into one ranked list:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/andersswanson/oracle-ai-database-examples/blob/main/langchain4j-agent-memory/src/main/java/dev/andersswanson/oracle/langchain4jmemory/MemoryRepository.java#L53-L63" rel="noopener noreferrer"&gt;Vector search&lt;/a&gt; over the &lt;code&gt;embedding&lt;/code&gt; column using cosine distance.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/andersswanson/oracle-ai-database-examples/blob/main/langchain4j-agent-memory/src/main/java/dev/andersswanson/oracle/langchain4jmemory/MemoryRepository.java#L65-L75" rel="noopener noreferrer"&gt;Oracle Text search&lt;/a&gt; over the JSON payload using &lt;code&gt;json_textcontains&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the vector query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;memory_kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;memory_doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;vector_distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;COSINE&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;vector_score&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;agent_memories&lt;/span&gt;
&lt;span class="k"&gt;order&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;vector_score&lt;/span&gt; &lt;span class="k"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;fetch&lt;/span&gt; &lt;span class="k"&gt;first&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="k"&gt;rows&lt;/span&gt; &lt;span class="k"&gt;only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is the text query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;memory_kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;memory_doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;text_score&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;agent_memories&lt;/span&gt;
&lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;json_textcontains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memory_doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'$'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;order&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;fetch&lt;/span&gt; &lt;span class="k"&gt;first&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="k"&gt;rows&lt;/span&gt; &lt;span class="k"&gt;only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pure vector search is often too fuzzy for ticket IDs. Pure text search is often too brittle for paraphrases. Hybrid retrieval handles both.&lt;/p&gt;

&lt;h4&gt;
  
  
  Lightweight reranking
&lt;/h4&gt;

&lt;p&gt;Once both branches return hits, &lt;a href="https://github.com/andersswanson/oracle-ai-database-examples/blob/main/langchain4j-agent-memory/src/main/java/dev/andersswanson/oracle/langchain4jmemory/MemorySearchRanker.java" rel="noopener noreferrer"&gt;&lt;code&gt;MemorySearchRanker&lt;/code&gt;&lt;/a&gt; merges the results with deterministic weights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a bonus when the incident ID or change ticket matches directly&lt;/li&gt;
&lt;li&gt;a bonus for keyword overlap in the indexed memory text&lt;/li&gt;
&lt;li&gt;a combined &lt;code&gt;matchedBy&lt;/code&gt; indicator of &lt;code&gt;VECTOR&lt;/code&gt;, &lt;code&gt;TEXT&lt;/code&gt;, or &lt;code&gt;BOTH&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The deterministic ranker could be implemented by an LLM judge or a more complex re-ranking system. For this sample, I kept it intentionally lightweight and low-latency.&lt;/p&gt;

&lt;h4&gt;
  
  
  LangChain4j agent
&lt;/h4&gt;

&lt;p&gt;The &lt;a href="https://github.com/andersswanson/oracle-ai-database-examples/blob/main/langchain4j-agent-memory/src/main/java/dev/andersswanson/oracle/langchain4jmemory/OpsMemoryAssistant.java" rel="noopener noreferrer"&gt;LangChain4j agent implementation&lt;/a&gt; is quite small, using a single interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;OpsMemoryAssistant&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@SystemMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""
            You are an operations handoff assistant backed by Oracle AI Database memory.
            Use searchMemories when prior incidents, runbooks, handoffs, decisions, or change history are relevant.
            When you rely on memory results, include the references in the form [M123].
            If the user asks you to remember or preserve a new handoff or decision, call storeMemory after drafting it.
            Keep answers concise and operational. Mention incident IDs and change tickets when they matter.
            """&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@UserMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{{message}}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@V&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;userMessage&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the right level of abstraction for this sample.&lt;/p&gt;

&lt;p&gt;LangChain4j handles chat orchestration and tool wiring. Oracle AI Database handles durable memory, search, and transcript persistence. Each layer is doing the job it is actually good at.&lt;/p&gt;

&lt;h4&gt;
  
  
  Memory writeback
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9u662b85vn3qic184gnd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9u662b85vn3qic184gnd.png" alt="Memory writeback" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The sample keeps two memory stores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a curated durable memory store for retrieval&lt;/li&gt;
&lt;li&gt;an append-only transcript for observability and auditing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This one also stores new durable memory through the &lt;code&gt;storeMemory&lt;/code&gt; tool when the user explicitly asks the assistant to preserve a handoff or decision.&lt;/p&gt;

&lt;p&gt;That matters because an agent memory system should not just be a read-only archive. If a useful conclusion comes out of a conversation, the system should be able to keep it.&lt;/p&gt;

&lt;p&gt;In this sample, writeback creates a new &lt;code&gt;MemoryDocument&lt;/code&gt;, generates an embedding, and inserts both the JSON payload and vector into &lt;code&gt;agent_memories&lt;/code&gt;. Because the JSON search index is configured with &lt;code&gt;sync (on commit)&lt;/code&gt;, newly stored handoffs are searchable immediately after commit.&lt;/p&gt;

&lt;p&gt;That last detail is important. Delayed indexing is exactly the kind of thing that makes an agent feel unreliable.&lt;/p&gt;

&lt;h4&gt;
  
  
  Recording user, agent, and tool messages
&lt;/h4&gt;

&lt;p&gt;With our database connection, it's easy to record chat sessions in the database. To do this with LangChain4j, we implement the ChatMemory interface in the &lt;a href="https://github.com/andersswanson/oracle-ai-database-examples/blob/main/langchain4j-agent-memory/src/main/java/dev/andersswanson/oracle/langchain4jmemory/LoggingChatMemory.java" rel="noopener noreferrer"&gt;LoggingChatMemory.java class&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Each session gets its own unique conversation ID, and user/agent/tool messages are written to the &lt;code&gt;agent_conversation_log&lt;/code&gt; table.&lt;/p&gt;

&lt;p&gt;That table captures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;conversation_id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;message_seq&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;role and message type&lt;/li&gt;
&lt;li&gt;message text&lt;/li&gt;
&lt;li&gt;tool name and tool call ID when relevant&lt;/li&gt;
&lt;li&gt;optional JSON context&lt;/li&gt;
&lt;li&gt;creation timestamp&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That distinction tends to get blurred in agent demos. It should not.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why database memory is useful for agents
&lt;/h4&gt;

&lt;p&gt;Chat windows and flat files can't scale the same way a database can. A database-backed memory layer gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;durable storage&lt;/li&gt;
&lt;li&gt;structured metadata&lt;/li&gt;
&lt;li&gt;many types of retrieval: semantic, text, relationship, graph, etc.&lt;/li&gt;
&lt;li&gt;transactional writes and concurrency&lt;/li&gt;
&lt;li&gt;better auditability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Databases can help you progress from agent demos to real applications that effectively utilize agent memory.&lt;/p&gt;

&lt;h4&gt;
  
  
  Code pointers
&lt;/h4&gt;

&lt;p&gt;If you want to explore the implementation, start here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/andersswanson/oracle-ai-database-examples/blob/main/langchain4j-agent-memory/README.md" rel="noopener noreferrer"&gt;README.md&lt;/a&gt; -&amp;gt; app overview&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/andersswanson/oracle-ai-database-examples/blob/main/langchain4j-agent-memory/src/main/java/dev/andersswanson/oracle/langchain4jmemory/OpsMemoryAgentApplication.java" rel="noopener noreferrer"&gt;OpsMemoryAgentApplication.java&lt;/a&gt; -&amp;gt; Main class and agent loop&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/andersswanson/oracle-ai-database-examples/blob/main/langchain4j-agent-memory/src/main/java/dev/andersswanson/oracle/langchain4jmemory/MemoryRepository.java" rel="noopener noreferrer"&gt;MemoryRepository.java&lt;/a&gt; -&amp;gt; Memory retrieval for text and vector search&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/andersswanson/oracle-ai-database-examples/blob/main/langchain4j-agent-memory/src/main/java/dev/andersswanson/oracle/langchain4jmemory/MemoryTools.java" rel="noopener noreferrer"&gt;MemoryTools.java&lt;/a&gt; -&amp;gt; LangChain4j tool bindings to search and store memories&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/andersswanson/oracle-ai-database-examples/blob/main/langchain4j-agent-memory/src/main/java/dev/andersswanson/oracle/langchain4jmemory/LoggingChatMemory.java" rel="noopener noreferrer"&gt;LoggingChatMemory.java&lt;/a&gt; -&amp;gt; LangChain4j ChatMemory implementation to log chat interactions&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/andersswanson/oracle-ai-database-examples/blob/main/langchain4j-agent-memory/src/test/java/dev/andersswanson/oracle/langchain4jmemory/MemoryRepositoryIntegrationTest.java" rel="noopener noreferrer"&gt;MemoryRepositoryIntegrationTest.java&lt;/a&gt; -&amp;gt; test using Oracle AI Database Free and Testcontainers&lt;/li&gt;
&lt;/ul&gt;

&lt;h6&gt;
  
  
  The tests validate the behavior that matters
&lt;/h6&gt;

&lt;p&gt;The integration tests are worth reading because they verify the actual retrieval patterns we care about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;exact text search finds the checkout incident for &lt;code&gt;CHG2145&lt;/code&gt; and &lt;code&gt;INC4721&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;vector search finds the same incident from a paraphrased outage description&lt;/li&gt;
&lt;li&gt;hybrid fusion marks the strongest result as matched by both channels&lt;/li&gt;
&lt;li&gt;a stored handoff can be found on the next combined search&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Where you can take this next
&lt;/h4&gt;

&lt;p&gt;If you'd like to extend this sample, here's a few ideas to play with:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add "forgetting" with recency ranking so newer memories are ranked as more relevant.&lt;/li&gt;
&lt;li&gt;Parameterize scoring and filtering mechanisms to make the app more flexible.&lt;/li&gt;
&lt;li&gt;Add another agent tool that uses an LLM to judge search results.&lt;/li&gt;
&lt;li&gt;Add approval/rejection when storing memories. Maintain a log of failures so the agent knows what not to do.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>oracle</category>
      <category>java</category>
      <category>agents</category>
      <category>ai</category>
    </item>
    <item>
      <title>Using Agent Skills to develop with Oracle AI Database</title>
      <dc:creator>Anders Swanson</dc:creator>
      <pubDate>Wed, 22 Apr 2026 17:19:24 +0000</pubDate>
      <link>https://dev.to/oracledevs/using-agent-skills-to-develop-with-oracle-ai-database-3h6j</link>
      <guid>https://dev.to/oracledevs/using-agent-skills-to-develop-with-oracle-ai-database-3h6j</guid>
      <description>&lt;p&gt;&lt;a href="https://anthropic.skilljar.com" rel="noopener noreferrer"&gt;Skills&lt;/a&gt; are reusable, task-specific workflows for your agents: each skill is a directory centered on a &lt;code&gt;SKILL.md&lt;/code&gt; file, with optional scripts, references, and assets packaged together.&lt;/p&gt;

&lt;p&gt;Skills bring context efficient capabilities to agents in a reliable, repeatable manner.&lt;/p&gt;

&lt;p&gt;In this article, we'll look at what skills are, how to install them, and how the open source &lt;a href="https://github.com/krisrice/oracle-db-skills" rel="noopener noreferrer"&gt;oracle-db-skills repo&lt;/a&gt; can help your agents do real work with Oracle AI Database. You can even easily write or extend the existing skills on your own!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install skills&lt;/li&gt;
&lt;li&gt;Using Oracle AI Database skills&lt;/li&gt;
&lt;li&gt;Have a suggestion or a new skill? Contribute it!&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Install skills
&lt;/h4&gt;

&lt;p&gt;First, install the skills into your agent. With Codex, you can use the skills installer. Make sure to restart Codex afterwards:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$skill&lt;/span&gt;&lt;span class="nt"&gt;-installer&lt;/span&gt; https://github.com/krisrice/oracle-db-skills
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Claude Code, either clone or copy the repo into your Claude-specific skills directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@github.com:krisrice/oracle-db-skills.git
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; oracle-db-skills ~/.claude/skills/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Using Oracle AI Database skills
&lt;/h4&gt;

&lt;p&gt;Let's use our newly installed skills to create a local Oracle AI Database Free container. These containers are great for local dev, POCs, and testing.&lt;/p&gt;

&lt;p&gt;Using Codex, we can explicitly invoke the skill using the &lt;code&gt;$oracle-db-skills&lt;/code&gt; skill command. With Claude Code, use &lt;code&gt;/oracle-db-skills&lt;/code&gt; to invoke the skill. Let's do so using the following prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$oracle-db-skills start a new oracle ai database container for local development and give me the sqlcl connection command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using this prompt, Codex inspected my local environment to ensure it could pull and run the container, and then ran the following command to start an Oracle AI Database Free container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;• Ran docker run -d --name oracle-ai-free -p 1521:1521 -e ORACLE_PWD=Oracle123! -v oracle-ai-free-data:/opt/oracle/oradata
  │ container-registry.oracle.com/database/free:latest
  └ b4daa0c4f9b5966087395005ddd251e68a7cdf1cae851b006cd7800da947fd04
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After verifying the container started correctly, Codex then gave me the following SQLcl commands to connect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;• Started a new Oracle AI Database Free container from the official image as oracle-ai-free. It's healthy on localhost:1521, and the PDB
  FREEPDB1 is open read/write.

  Use SQLcl like this for normal development work:

  sql system/Oracle123!@//localhost:1521/FREEPDB1

  If you need SYSDBA, use:

  sql sys/Oracle123!@//localhost:1521/FREE as sysdba
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both of which connect to the container started by the agent, using the skill.&lt;/p&gt;

&lt;h4&gt;
  
  
  Have a suggestion or a new skill? Contribute it!
&lt;/h4&gt;

&lt;p&gt;The &lt;a href="https://github.com/krisrice/oracle-db-skills" rel="noopener noreferrer"&gt;oracle-db-skills GitHub repo&lt;/a&gt; is open source, so if you have an idea or suggestion, go ahead and contribute it. The repo is designed to be an evolving set of curated skills, meaning developer feedback is essential.&lt;/p&gt;

</description>
      <category>oracle</category>
      <category>ai</category>
      <category>agents</category>
      <category>software</category>
    </item>
  </channel>
</rss>
